diff options
author | Vsevolod Stakhov <vsevolod@rspamd.com> | 2024-09-05 16:20:46 +0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-05 16:20:46 +0600 |
commit | 737a2ce03b826f86851d021d628274ab8c8ea7fb (patch) | |
tree | 7918e548808c5981fab465726f545a5c6cc9fe49 /src | |
parent | dd47f82a317ad2ed9a9270c9779bf866ff5989fd (diff) | |
parent | 40a6ddd69be80e6a4ad8a29053bbfa18d24b3bd8 (diff) | |
download | rspamd-737a2ce03b826f86851d021d628274ab8c8ea7fb.tar.gz rspamd-737a2ce03b826f86851d021d628274ab8c8ea7fb.zip |
Merge branch 'master' into vstakhov-utf8-mime
Diffstat (limited to 'src')
47 files changed, 1632 insertions, 2480 deletions
diff --git a/src/client/rspamc.cxx b/src/client/rspamc.cxx index 1e0830493..1c67e4167 100644 --- a/src/client/rspamc.cxx +++ b/src/client/rspamc.cxx @@ -524,16 +524,13 @@ rspamc_password_callback(const char *option_name, else { /* Strip trailing spaces */ auto *map = (char *) locked_mmap.value().get_map(); - auto *end = map + locked_mmap.value().get_size() - 1; - - while (g_ascii_isspace(*end) && end > map) { - end--; - } - - end++; - value_view = std::string_view{map, static_cast<std::size_t>(end - map + 1)}; - processed_passwd.assign(std::begin(value_view), std::end(value_view)); - processed_passwd.push_back('\0'); + value_view = std::string_view{map, locked_mmap->get_size()}; + auto right = value_view.end() - 1; + for (; right > value_view.cbegin() && g_ascii_isspace(*right); --right) + ; + std::string_view str{value_view.begin(), static_cast<size_t>(right - value_view.begin()) + 1}; + processed_passwd.assign(std::begin(str), std::end(str)); + processed_passwd.push_back('\0'); /* Null-terminate for C part */ } } else { diff --git a/src/client/rspamdclient.c b/src/client/rspamdclient.c index 2b8d0e9bb..bcb3cf67c 100644 --- a/src/client/rspamdclient.c +++ b/src/client/rspamdclient.c @@ -302,12 +302,10 @@ rspamd_client_init(struct rspamd_http_context *http_ctx, conn->timeout = timeout; if (key) { - conn->key = rspamd_pubkey_from_base32(key, 0, RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + conn->key = rspamd_pubkey_from_base32(key, 0, RSPAMD_KEYPAIR_KEX); if (conn->key) { - conn->keypair = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + conn->keypair = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX); rspamd_http_connection_set_key(conn->http_conn, conn->keypair); } else { diff --git a/src/controller.c b/src/controller.c index d91f99098..386448f93 100644 --- a/src/controller.c +++ b/src/controller.c @@ -1945,7 +1945,7 @@ rspamd_controller_learn_fin_task(void *ud) if (task->err != NULL) { msg_info_session("cannot learn <%s>: %e", - MESSAGE_FIELD(task, message_id), task->err); + MESSAGE_FIELD_CHECK(task, message_id), task->err); rspamd_controller_send_error(conn_ent, task->err->code, "%s", task->err->message); @@ -1957,14 +1957,14 @@ rspamd_controller_learn_fin_task(void *ud) msg_info_task("<%s> learned message as %s: %s", rspamd_inet_address_to_string(session->from_addr), session->is_spam ? "spam" : "ham", - MESSAGE_FIELD(task, message_id)); + MESSAGE_FIELD_CHECK(task, message_id)); rspamd_controller_send_string(conn_ent, "{\"success\":true}"); return TRUE; } if (!rspamd_task_process(task, RSPAMD_TASK_PROCESS_LEARN)) { msg_info_task("cannot learn <%s>: %e", - MESSAGE_FIELD(task, message_id), task->err); + MESSAGE_FIELD_CHECK(task, message_id), task->err); if (task->err) { rspamd_controller_send_error(conn_ent, task->err->code, "%s", @@ -1985,7 +1985,7 @@ rspamd_controller_learn_fin_task(void *ud) msg_info_task("<%s> learned message as %s: %s", rspamd_inet_address_to_string(session->from_addr), session->is_spam ? "spam" : "ham", - MESSAGE_FIELD(task, message_id)); + MESSAGE_FIELD_CHECK(task, message_id)); rspamd_controller_send_string(conn_ent, "{\"success\":true}"); } @@ -2114,7 +2114,7 @@ rspamd_controller_handle_learn_common( if (!rspamd_task_process(task, RSPAMD_TASK_PROCESS_LEARN)) { msg_warn_session("<%s> message cannot be processed", - MESSAGE_FIELD(task, message_id)); + MESSAGE_FIELD_CHECK(task, message_id)); goto end; } diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c index 445289511..5fd3303dc 100644 --- a/src/fuzzy_storage.c +++ b/src/fuzzy_storage.c @@ -1088,8 +1088,7 @@ rspamd_fuzzy_make_reply(struct rspamd_fuzzy_cmd *cmd, len, session->reply.hdr.nonce, session->nm, - session->reply.hdr.mac, - RSPAMD_CRYPTOBOX_MODE_25519); + session->reply.hdr.mac); } else if (default_disabled) { /* Hash is from a forbidden flag by default, and there is no encryption override */ @@ -1668,8 +1667,7 @@ rspamd_fuzzy_decrypt_command(struct fuzzy_session *s, unsigned char *buf, gsize } /* Now process the remote pubkey */ - rk = rspamd_pubkey_from_bin(hdr.pubkey, sizeof(hdr.pubkey), - RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); + rk = rspamd_pubkey_from_bin(hdr.pubkey, sizeof(hdr.pubkey), RSPAMD_KEYPAIR_KEX); if (rk == NULL) { msg_err("bad key; ip=%s", @@ -1683,7 +1681,7 @@ rspamd_fuzzy_decrypt_command(struct fuzzy_session *s, unsigned char *buf, gsize /* Now decrypt request */ if (!rspamd_cryptobox_decrypt_nm_inplace(buf, buflen, hdr.nonce, rspamd_pubkey_get_nm(rk, key->key), - hdr.mac, RSPAMD_CRYPTOBOX_MODE_25519)) { + hdr.mac)) { msg_err("decryption failed; ip=%s", rspamd_inet_address_to_string(s->addr)); rspamd_pubkey_unref(rk); @@ -2771,8 +2769,7 @@ fuzzy_add_keypair_from_ucl(const ucl_object_t *obj, khash_t(rspamd_fuzzy_keys_ha return NULL; } - if (rspamd_keypair_alg(kp) != RSPAMD_CRYPTOBOX_MODE_25519 || - rspamd_keypair_type(kp) != RSPAMD_KEYPAIR_KEX) { + if (rspamd_keypair_type(kp) != RSPAMD_KEYPAIR_KEX) { return FALSE; } @@ -2837,7 +2834,7 @@ fuzzy_add_keypair_from_ucl(const ucl_object_t *obj, khash_t(rspamd_fuzzy_keys_ha } } - msg_debug("loaded keypair %*bs", rspamd_cryptobox_pk_bytes(RSPAMD_CRYPTOBOX_MODE_25519), pk); + msg_debug("loaded keypair %*bs", crypto_box_publickeybytes(), pk); return key; } diff --git a/src/libcryptobox/cryptobox.c b/src/libcryptobox/cryptobox.c index aa093d01e..eeeed020c 100644 --- a/src/libcryptobox/cryptobox.c +++ b/src/libcryptobox/cryptobox.c @@ -38,19 +38,8 @@ #endif #ifdef HAVE_OPENSSL #include <openssl/opensslv.h> -/* Openssl >= 1.0.1d is required for GCM verification */ -#if OPENSSL_VERSION_NUMBER >= 0x1000104fL -#define HAVE_USABLE_OPENSSL 1 -#endif -#endif - -#ifdef HAVE_USABLE_OPENSSL #include <openssl/evp.h> -#include <openssl/ec.h> -#include <openssl/ecdh.h> -#include <openssl/ecdsa.h> -#include <openssl/rand.h> -#define CRYPTOBOX_CURVE_NID NID_X9_62_prime256v1 +#include <openssl/rsa.h> #endif #include <signal.h> @@ -324,759 +313,327 @@ void rspamd_cryptobox_deinit(struct rspamd_cryptobox_library_ctx *ctx) } } -void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk, - enum rspamd_cryptobox_mode mode) +void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - ottery_rand_bytes(sk, rspamd_cryptobox_MAX_SKBYTES); - sk[0] &= 248; - sk[31] &= 127; - sk[31] |= 64; - - crypto_scalarmult_base(pk, sk); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EC_KEY *ec_sec; - const BIGNUM *bn_sec; - - const EC_POINT *ec_pub; - gsize len; - - ec_sec = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID); - g_assert(ec_sec != NULL); - g_assert(EC_KEY_generate_key(ec_sec) != 0); - - bn_sec = EC_KEY_get0_private_key(ec_sec); - g_assert(bn_sec != NULL); - ec_pub = EC_KEY_get0_public_key(ec_sec); - g_assert(ec_pub != NULL); -#if OPENSSL_VERSION_MAJOR >= 3 - unsigned char *buf = NULL; /* Thanks openssl for this API (no) */ - len = EC_POINT_point2buf(EC_KEY_get0_group(ec_sec), ec_pub, - POINT_CONVERSION_UNCOMPRESSED, &buf, NULL); - g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode)); - memcpy(pk, buf, len); - OPENSSL_free(buf); -#else - BIGNUM *bn_pub; - bn_pub = EC_POINT_point2bn(EC_KEY_get0_group(ec_sec), - ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); - len = BN_num_bytes(bn_pub); - g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode)); - BN_bn2bin(bn_pub, pk); - BN_free(bn_pub); -#endif + ottery_rand_bytes(sk, rspamd_cryptobox_MAX_SKBYTES); + sk[0] &= 248; + sk[31] &= 127; + sk[31] |= 64; - len = BN_num_bytes(bn_sec); - g_assert(len <= (int) sizeof(rspamd_sk_t)); - BN_bn2bin(bn_sec, sk); + crypto_scalarmult_base(pk, sk); +} - EC_KEY_free(ec_sec); -#endif - } +void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk) +{ + crypto_sign_keypair(pk, sk); } -void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk, - enum rspamd_cryptobox_mode mode) +void rspamd_cryptobox_nm(rspamd_nm_t nm, + const rspamd_pk_t pk, const rspamd_sk_t sk) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_sign_keypair(pk, sk); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EC_KEY *ec_sec; - const BIGNUM *bn_sec; - const EC_POINT *ec_pub; - gsize len; - - ec_sec = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID); - g_assert(ec_sec != NULL); - g_assert(EC_KEY_generate_key(ec_sec) != 0); - - bn_sec = EC_KEY_get0_private_key(ec_sec); - g_assert(bn_sec != NULL); - ec_pub = EC_KEY_get0_public_key(ec_sec); - g_assert(ec_pub != NULL); - -#if OPENSSL_VERSION_MAJOR >= 3 - unsigned char *buf = NULL; /* Thanks openssl for this API (no) */ - len = EC_POINT_point2buf(EC_KEY_get0_group(ec_sec), ec_pub, - POINT_CONVERSION_UNCOMPRESSED, &buf, NULL); - g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode)); - memcpy(pk, buf, len); - OPENSSL_free(buf); -#else - BIGNUM *bn_pub; - bn_pub = EC_POINT_point2bn(EC_KEY_get0_group(ec_sec), - ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); - len = BN_num_bytes(bn_pub); - g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode)); - BN_bn2bin(bn_pub, pk); - BN_free(bn_pub); -#endif + unsigned char s[32]; + unsigned char e[32]; - len = BN_num_bytes(bn_sec); - g_assert(len <= (int) sizeof(rspamd_sk_t)); - BN_bn2bin(bn_sec, sk); - EC_KEY_free(ec_sec); -#endif + memcpy(e, sk, 32); + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + if (crypto_scalarmult(s, e, pk) != -1) { + hchacha(s, n0, nm, 20); } + + rspamd_explicit_memzero(e, 32); } -#if OPENSSL_VERSION_MAJOR >= 3 -/* Compatibility function for OpenSSL 3.0 - thanks for breaking all API one more time */ -EC_POINT *ec_point_bn2point_compat(const EC_GROUP *group, - const BIGNUM *bn, EC_POINT *point, BN_CTX *ctx) +void rspamd_cryptobox_sign(unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, gsize mlen, + const rspamd_sig_sk_t sk) { - size_t buf_len = 0; - unsigned char *buf; - EC_POINT *ret; - - if ((buf_len = BN_num_bytes(bn)) == 0) - buf_len = 1; - if ((buf = OPENSSL_malloc(buf_len)) == NULL) { - return NULL; - } + crypto_sign_detached(sig, siglen_p, m, mlen, sk); +} - if (!BN_bn2binpad(bn, buf, buf_len)) { - OPENSSL_free(buf); - return NULL; - } +#ifdef HAVE_OPENSSL +bool rspamd_cryptobox_verify_evp_ed25519(int nid, + const unsigned char *sig, + gsize siglen, + const unsigned char *digest, + gsize dlen, + struct evp_pkey_st *pub_key) +{ + bool ret = false; - if (point == NULL) { - if ((ret = EC_POINT_new(group)) == NULL) { - OPENSSL_free(buf); - return NULL; - } - } - else - ret = point; - - if (!EC_POINT_oct2point(group, ret, buf, buf_len, ctx)) { - if (ret != point) - EC_POINT_clear_free(ret); - OPENSSL_free(buf); - return NULL; + if (siglen == crypto_sign_bytes()) { + rspamd_pk_t pk; + size_t len_pk = sizeof(rspamd_pk_t); + EVP_PKEY_get_raw_public_key(pub_key, pk, &len_pk); + ret = (crypto_sign_verify_detached(sig, digest, dlen, pk) == 0); } - OPENSSL_free(buf); return ret; } -#else -#define ec_point_bn2point_compat EC_POINT_bn2point -#endif -void rspamd_cryptobox_nm(rspamd_nm_t nm, - const rspamd_pk_t pk, const rspamd_sk_t sk, - enum rspamd_cryptobox_mode mode) +bool rspamd_cryptobox_verify_evp_ecdsa(int nid, + const unsigned char *sig, + gsize siglen, + const unsigned char *digest, + gsize dlen, + EVP_PKEY *pub_key) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - unsigned char s[32]; - unsigned char e[32]; + bool ret = false; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pub_key, NULL); + g_assert(pctx != NULL); + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); + const EVP_MD *md = EVP_get_digestbynid(nid); - memcpy(e, sk, 32); - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; + g_assert(EVP_PKEY_verify_init(pctx) == 1); + g_assert(EVP_PKEY_CTX_set_signature_md(pctx, md) == 1); - if (crypto_scalarmult(s, e, pk) != -1) { - hchacha(s, n0, nm, 20); - } + ret = (EVP_PKEY_verify(pctx, sig, siglen, digest, dlen) == 1); - rspamd_explicit_memzero(e, 32); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EC_KEY *lk; - EC_POINT *ec_pub; - BIGNUM *bn_pub, *bn_sec; - int len; - unsigned char s[32]; - - lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID); - g_assert(lk != NULL); - - bn_pub = BN_bin2bn(pk, rspamd_cryptobox_pk_bytes(mode), NULL); - g_assert(bn_pub != NULL); - bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL); - g_assert(bn_sec != NULL); - - g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1); - ec_pub = ec_point_bn2point_compat(EC_KEY_get0_group(lk), bn_pub, NULL, NULL); - g_assert(ec_pub != NULL); - len = ECDH_compute_key(s, sizeof(s), ec_pub, lk, NULL); - g_assert(len == sizeof(s)); - - /* Still do hchacha iteration since we are not using SHA1 KDF */ - hchacha(s, n0, nm, 20); + EVP_PKEY_CTX_free(pctx); + EVP_MD_CTX_free(mdctx); - EC_KEY_free(lk); - EC_POINT_free(ec_pub); - BN_free(bn_sec); - BN_free(bn_pub); -#endif - } + return ret; } - -void rspamd_cryptobox_sign(unsigned char *sig, unsigned long long *siglen_p, - const unsigned char *m, gsize mlen, - const rspamd_sk_t sk, - enum rspamd_cryptobox_mode mode) +bool rspamd_cryptobox_verify_evp_rsa(int nid, + const unsigned char *sig, + gsize siglen, + const unsigned char *digest, + gsize dlen, + EVP_PKEY *pub_key) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_sign_detached(sig, siglen_p, m, mlen, sk); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EC_KEY *lk; - BIGNUM *bn_sec; - EVP_MD_CTX *sha_ctx; - unsigned char h[64]; - unsigned int diglen = rspamd_cryptobox_signature_bytes(mode); - - /* Prehash */ - sha_ctx = EVP_MD_CTX_create(); - g_assert(EVP_DigestInit(sha_ctx, EVP_sha512()) == 1); - EVP_DigestUpdate(sha_ctx, m, mlen); - EVP_DigestFinal(sha_ctx, h, NULL); - - /* Key setup */ - lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID); - g_assert(lk != NULL); - bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL); - g_assert(bn_sec != NULL); - g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1); - - /* ECDSA */ - g_assert(ECDSA_sign(0, h, sizeof(h), sig, &diglen, lk) == 1); - g_assert(diglen <= sizeof(rspamd_signature_t)); - - if (siglen_p) { - *siglen_p = diglen; - } + bool ret = false; - EC_KEY_free(lk); - EVP_MD_CTX_destroy(sha_ctx); - BN_free(bn_sec); -#endif - } + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pub_key, NULL); + g_assert(pctx != NULL); + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); + const EVP_MD *md = EVP_get_digestbynid(nid); + + g_assert(EVP_PKEY_verify_init(pctx) == 1); + g_assert(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) == 1); + g_assert(EVP_PKEY_CTX_set_signature_md(pctx, md) == 1); + + ret = (EVP_PKEY_verify(pctx, sig, siglen, digest, dlen) == 1); + + EVP_PKEY_CTX_free(pctx); + EVP_MD_CTX_free(mdctx); + + return ret; } +#endif bool rspamd_cryptobox_verify(const unsigned char *sig, gsize siglen, const unsigned char *m, gsize mlen, - const rspamd_pk_t pk, - enum rspamd_cryptobox_mode mode) + const rspamd_sig_pk_t pk) { bool ret = false; - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - if (siglen == rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519)) { - ret = (crypto_sign_verify_detached(sig, m, mlen, pk) == 0); - } - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EC_KEY *lk; - EC_POINT *ec_pub; - BIGNUM *bn_pub; - EVP_MD_CTX *sha_ctx; - unsigned char h[64]; - - /* Prehash */ - sha_ctx = EVP_MD_CTX_create(); - g_assert(EVP_DigestInit(sha_ctx, EVP_sha512()) == 1); - EVP_DigestUpdate(sha_ctx, m, mlen); - EVP_DigestFinal(sha_ctx, h, NULL); - - /* Key setup */ - lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID); - g_assert(lk != NULL); - bn_pub = BN_bin2bn(pk, rspamd_cryptobox_pk_bytes(mode), NULL); - g_assert(bn_pub != NULL); - ec_pub = ec_point_bn2point_compat(EC_KEY_get0_group(lk), bn_pub, NULL, NULL); - g_assert(ec_pub != NULL); - g_assert(EC_KEY_set_public_key(lk, ec_pub) == 1); - - /* ECDSA */ - ret = ECDSA_verify(0, h, sizeof(h), sig, siglen, lk) == 1; - - EC_KEY_free(lk); - EVP_MD_CTX_destroy(sha_ctx); - BN_free(bn_pub); - EC_POINT_free(ec_pub); -#endif + if (siglen == crypto_sign_bytes()) { + ret = (crypto_sign_verify_detached(sig, m, mlen, pk) == 0); } return ret; } -static gsize -rspamd_cryptobox_encrypt_ctx_len(enum rspamd_cryptobox_mode mode) -{ - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return sizeof(chacha_state) + CRYPTOBOX_ALIGNMENT; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - return sizeof(EVP_CIPHER_CTX *) + CRYPTOBOX_ALIGNMENT; -#endif - } - - return 0; -} - -static gsize -rspamd_cryptobox_auth_ctx_len(enum rspamd_cryptobox_mode mode) -{ - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return sizeof(crypto_onetimeauth_state) + RSPAMD_ALIGNOF(crypto_onetimeauth_state); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - return sizeof(void *); -#endif - } - - return 0; -} - static void * rspamd_cryptobox_encrypt_init(void *enc_ctx, const rspamd_nonce_t nonce, - const rspamd_nm_t nm, - enum rspamd_cryptobox_mode mode) + const rspamd_nm_t nm) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - chacha_state *s; + chacha_state *s; - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - xchacha_init(s, - (const chacha_key *) nm, - (const chacha_iv24 *) nonce, - 20); - - return s; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s; - - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - memset(s, 0, sizeof(*s)); - *s = EVP_CIPHER_CTX_new(); - g_assert(EVP_EncryptInit_ex(*s, EVP_aes_256_gcm(), NULL, NULL, NULL) == 1); - g_assert(EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_SET_IVLEN, - rspamd_cryptobox_nonce_bytes(mode), NULL) == 1); - g_assert(EVP_EncryptInit_ex(*s, NULL, NULL, nm, nonce) == 1); - - return s; -#endif - } + s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); + xchacha_init(s, + (const chacha_key *) nm, + (const chacha_iv24 *) nonce, + 20); - return NULL; + return s; } static void * -rspamd_cryptobox_auth_init(void *auth_ctx, void *enc_ctx, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_auth_init(void *auth_ctx, void *enc_ctx) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_onetimeauth_state *mac_ctx; - unsigned char RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES]; - - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - memset(subkey, 0, sizeof(subkey)); - chacha_update(enc_ctx, subkey, subkey, sizeof(subkey)); - crypto_onetimeauth_init(mac_ctx, subkey); - rspamd_explicit_memzero(subkey, sizeof(subkey)); - - return mac_ctx; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - auth_ctx = enc_ctx; + crypto_onetimeauth_state *mac_ctx; + unsigned char RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES]; - return auth_ctx; -#endif - } + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + memset(subkey, 0, sizeof(subkey)); + chacha_update(enc_ctx, subkey, subkey, sizeof(subkey)); + crypto_onetimeauth_init(mac_ctx, subkey); + rspamd_explicit_memzero(subkey, sizeof(subkey)); - return NULL; + return mac_ctx; } static gboolean rspamd_cryptobox_encrypt_update(void *enc_ctx, const unsigned char *in, gsize inlen, - unsigned char *out, gsize *outlen, - enum rspamd_cryptobox_mode mode) + unsigned char *out, gsize *outlen) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - gsize r; - chacha_state *s; - - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - - r = chacha_update(s, in, out, inlen); - - if (outlen != NULL) { - *outlen = r; - } - - return TRUE; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = enc_ctx; - int r; + gsize r; + chacha_state *s; - r = inlen; - g_assert(EVP_EncryptUpdate(*s, out, &r, in, inlen) == 1); + s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - if (outlen) { - *outlen = r; - } + r = chacha_update(s, in, out, inlen); - return TRUE; -#endif + if (outlen != NULL) { + *outlen = r; } - return FALSE; + return TRUE; } static gboolean -rspamd_cryptobox_auth_update(void *auth_ctx, const unsigned char *in, gsize inlen, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_auth_update(void *auth_ctx, const unsigned char *in, gsize inlen) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_onetimeauth_state *mac_ctx; + crypto_onetimeauth_state *mac_ctx; - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - crypto_onetimeauth_update(mac_ctx, in, inlen); + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + crypto_onetimeauth_update(mac_ctx, in, inlen); - return TRUE; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - return TRUE; -#endif - } - - return FALSE; + return TRUE; } static gsize -rspamd_cryptobox_encrypt_final(void *enc_ctx, unsigned char *out, gsize remain, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_encrypt_final(void *enc_ctx, unsigned char *out, gsize remain) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - chacha_state *s; - - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - return chacha_final(s, out); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = enc_ctx; - int r = remain; + chacha_state *s; - g_assert(EVP_EncryptFinal_ex(*s, out, &r) == 1); - - return r; -#endif - } - - return 0; + s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); + return chacha_final(s, out); } static gboolean -rspamd_cryptobox_auth_final(void *auth_ctx, rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_auth_final(void *auth_ctx, rspamd_mac_t sig) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_onetimeauth_state *mac_ctx; - - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - crypto_onetimeauth_final(mac_ctx, sig); - - return TRUE; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = auth_ctx; - - g_assert(EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_GET_TAG, - sizeof(rspamd_mac_t), sig) == 1); + crypto_onetimeauth_state *mac_ctx; - return TRUE; -#endif - } + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + crypto_onetimeauth_final(mac_ctx, sig); - return FALSE; + return TRUE; } static void * rspamd_cryptobox_decrypt_init(void *enc_ctx, const rspamd_nonce_t nonce, - const rspamd_nm_t nm, - enum rspamd_cryptobox_mode mode) + const rspamd_nm_t nm) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - - chacha_state *s; + chacha_state *s; - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - xchacha_init(s, - (const chacha_key *) nm, - (const chacha_iv24 *) nonce, - 20); + s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); + xchacha_init(s, + (const chacha_key *) nm, + (const chacha_iv24 *) nonce, + 20); - return s; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s; - - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - memset(s, 0, sizeof(*s)); - *s = EVP_CIPHER_CTX_new(); - g_assert(EVP_DecryptInit_ex(*s, EVP_aes_256_gcm(), NULL, NULL, NULL) == 1); - g_assert(EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_SET_IVLEN, - rspamd_cryptobox_nonce_bytes(mode), NULL) == 1); - g_assert(EVP_DecryptInit_ex(*s, NULL, NULL, nm, nonce) == 1); - - return s; -#endif - } - - return NULL; + return s; } static void * -rspamd_cryptobox_auth_verify_init(void *auth_ctx, void *enc_ctx, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_auth_verify_init(void *auth_ctx, void *enc_ctx) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_onetimeauth_state *mac_ctx; - unsigned char RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES]; + crypto_onetimeauth_state *mac_ctx; + unsigned char RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES]; - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - memset(subkey, 0, sizeof(subkey)); - chacha_update(enc_ctx, subkey, subkey, sizeof(subkey)); - crypto_onetimeauth_init(mac_ctx, subkey); - rspamd_explicit_memzero(subkey, sizeof(subkey)); + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + memset(subkey, 0, sizeof(subkey)); + chacha_update(enc_ctx, subkey, subkey, sizeof(subkey)); + crypto_onetimeauth_init(mac_ctx, subkey); + rspamd_explicit_memzero(subkey, sizeof(subkey)); - return mac_ctx; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - auth_ctx = enc_ctx; - - return auth_ctx; -#endif - } - - return NULL; + return mac_ctx; } static gboolean rspamd_cryptobox_decrypt_update(void *enc_ctx, const unsigned char *in, gsize inlen, - unsigned char *out, gsize *outlen, - enum rspamd_cryptobox_mode mode) + unsigned char *out, gsize *outlen) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - gsize r; - chacha_state *s; - - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - r = chacha_update(s, in, out, inlen); + gsize r; + chacha_state *s; - if (outlen != NULL) { - *outlen = r; - } + s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); + r = chacha_update(s, in, out, inlen); - return TRUE; + if (outlen != NULL) { + *outlen = r; } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = enc_ctx; - int r; - - r = outlen ? *outlen : inlen; - g_assert(EVP_DecryptUpdate(*s, out, &r, in, inlen) == 1); - if (outlen) { - *outlen = r; - } - - return TRUE; -#endif - } + return TRUE; } static gboolean rspamd_cryptobox_auth_verify_update(void *auth_ctx, - const unsigned char *in, gsize inlen, - enum rspamd_cryptobox_mode mode) + const unsigned char *in, gsize inlen) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_onetimeauth_state *mac_ctx; - - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - crypto_onetimeauth_update(mac_ctx, in, inlen); + crypto_onetimeauth_state *mac_ctx; - return TRUE; - } - else { -#ifndef HAVE_USABLE_OPENSSL - /* We do not need to authenticate as a separate process */ - return TRUE; -#else -#endif - } + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + crypto_onetimeauth_update(mac_ctx, in, inlen); - return FALSE; + return TRUE; } static gboolean -rspamd_cryptobox_decrypt_final(void *enc_ctx, unsigned char *out, gsize remain, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_decrypt_final(void *enc_ctx, unsigned char *out, gsize remain) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - chacha_state *s; + chacha_state *s; - s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); - chacha_final(s, out); + s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT); + chacha_final(s, out); - return TRUE; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = enc_ctx; - int r = remain; - - if (EVP_DecryptFinal_ex(*s, out, &r) < 0) { - return FALSE; - } - - return TRUE; -#endif - } - - return FALSE; + return TRUE; } static gboolean -rspamd_cryptobox_auth_verify_final(void *auth_ctx, const rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_auth_verify_final(void *auth_ctx, const rspamd_mac_t sig) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - rspamd_mac_t mac; - crypto_onetimeauth_state *mac_ctx; + rspamd_mac_t mac; + crypto_onetimeauth_state *mac_ctx; - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - crypto_onetimeauth_final(mac_ctx, mac); - - if (crypto_verify_16(mac, sig) != 0) { - return FALSE; - } + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + crypto_onetimeauth_final(mac_ctx, mac); - return TRUE; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = auth_ctx; - - if (EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *) sig) != 1) { - return FALSE; - } - - return TRUE; -#endif + if (crypto_verify_16(mac, sig) != 0) { + return FALSE; } - return FALSE; + return TRUE; } static void -rspamd_cryptobox_cleanup(void *enc_ctx, void *auth_ctx, - enum rspamd_cryptobox_mode mode) +rspamd_cryptobox_cleanup(void *enc_ctx, void *auth_ctx) { - if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - crypto_onetimeauth_state *mac_ctx; - - mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); - rspamd_explicit_memzero(mac_ctx, sizeof(*mac_ctx)); - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - EVP_CIPHER_CTX **s = enc_ctx; + crypto_onetimeauth_state *mac_ctx; - EVP_CIPHER_CTX_cleanup(*s); - EVP_CIPHER_CTX_free(*s); -#endif - } + mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT); + rspamd_explicit_memzero(mac_ctx, sizeof(*mac_ctx)); } void rspamd_cryptobox_encrypt_nm_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, const rspamd_nm_t nm, - rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) + rspamd_mac_t sig) { gsize r; void *enc_ctx, *auth_ctx; - enc_ctx = g_alloca(rspamd_cryptobox_encrypt_ctx_len(mode)); - auth_ctx = g_alloca(rspamd_cryptobox_auth_ctx_len(mode)); + enc_ctx = g_alloca(sizeof(chacha_state) + CRYPTOBOX_ALIGNMENT); + auth_ctx = g_alloca(sizeof(crypto_onetimeauth_state) + RSPAMD_ALIGNOF(crypto_onetimeauth_state)); - enc_ctx = rspamd_cryptobox_encrypt_init(enc_ctx, nonce, nm, mode); - auth_ctx = rspamd_cryptobox_auth_init(auth_ctx, enc_ctx, mode); + enc_ctx = rspamd_cryptobox_encrypt_init(enc_ctx, nonce, nm); + auth_ctx = rspamd_cryptobox_auth_init(auth_ctx, enc_ctx); - rspamd_cryptobox_encrypt_update(enc_ctx, data, len, data, &r, mode); - rspamd_cryptobox_encrypt_final(enc_ctx, data + r, len - r, mode); + rspamd_cryptobox_encrypt_update(enc_ctx, data, len, data, &r); + rspamd_cryptobox_encrypt_final(enc_ctx, data + r, len - r); - rspamd_cryptobox_auth_update(auth_ctx, data, len, mode); - rspamd_cryptobox_auth_final(auth_ctx, sig, mode); + rspamd_cryptobox_auth_update(auth_ctx, data, len); + rspamd_cryptobox_auth_final(auth_ctx, sig); - rspamd_cryptobox_cleanup(enc_ctx, auth_ctx, mode); + rspamd_cryptobox_cleanup(enc_ctx, auth_ctx); } static void @@ -1098,8 +655,7 @@ rspamd_cryptobox_flush_outbuf(struct rspamd_cryptobox_segment *st, void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segments, gsize cnt, const rspamd_nonce_t nonce, - const rspamd_nm_t nm, rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) + const rspamd_nm_t nm, rspamd_mac_t sig) { struct rspamd_cryptobox_segment *cur = segments, *start_seg = segments; unsigned char outbuf[CHACHA_BLOCKBYTES * 16]; @@ -1107,11 +663,11 @@ void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segme unsigned char *out, *in; gsize r, remain, inremain, seg_offset; - enc_ctx = g_alloca(rspamd_cryptobox_encrypt_ctx_len(mode)); - auth_ctx = g_alloca(rspamd_cryptobox_auth_ctx_len(mode)); + enc_ctx = g_alloca(sizeof(chacha_state) + CRYPTOBOX_ALIGNMENT); + auth_ctx = g_alloca(sizeof(crypto_onetimeauth_state) + RSPAMD_ALIGNOF(crypto_onetimeauth_state)); - enc_ctx = rspamd_cryptobox_encrypt_init(enc_ctx, nonce, nm, mode); - auth_ctx = rspamd_cryptobox_auth_init(auth_ctx, enc_ctx, mode); + enc_ctx = rspamd_cryptobox_encrypt_init(enc_ctx, nonce, nm); + auth_ctx = rspamd_cryptobox_auth_init(auth_ctx, enc_ctx); remain = sizeof(outbuf); out = outbuf; @@ -1131,9 +687,8 @@ void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segme if (remain == 0) { rspamd_cryptobox_encrypt_update(enc_ctx, outbuf, sizeof(outbuf), - outbuf, NULL, mode); - rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf), - mode); + outbuf, NULL); + rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf)); rspamd_cryptobox_flush_outbuf(start_seg, outbuf, sizeof(outbuf), seg_offset); start_seg = cur; @@ -1145,9 +700,8 @@ void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segme else { memcpy(out, cur->data, remain); rspamd_cryptobox_encrypt_update(enc_ctx, outbuf, sizeof(outbuf), - outbuf, NULL, mode); - rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf), - mode); + outbuf, NULL); + rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf)); rspamd_cryptobox_flush_outbuf(start_seg, outbuf, sizeof(outbuf), seg_offset); seg_offset = 0; @@ -1165,12 +719,10 @@ void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segme outbuf, sizeof(outbuf), outbuf, - NULL, - mode); + NULL); rspamd_cryptobox_auth_update(auth_ctx, outbuf, - sizeof(outbuf), - mode); + sizeof(outbuf)); memcpy(in, outbuf, sizeof(outbuf)); in += sizeof(outbuf); inremain -= sizeof(outbuf); @@ -1190,46 +742,44 @@ void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segme } rspamd_cryptobox_encrypt_update(enc_ctx, outbuf, sizeof(outbuf) - remain, - outbuf, &r, mode); + outbuf, &r); out = outbuf + r; - rspamd_cryptobox_encrypt_final(enc_ctx, out, sizeof(outbuf) - remain - r, - mode); + rspamd_cryptobox_encrypt_final(enc_ctx, out, sizeof(outbuf) - remain - r); - rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf) - remain, - mode); - rspamd_cryptobox_auth_final(auth_ctx, sig, mode); + rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf) - remain); + rspamd_cryptobox_auth_final(auth_ctx, sig); rspamd_cryptobox_flush_outbuf(start_seg, outbuf, sizeof(outbuf) - remain, seg_offset); - rspamd_cryptobox_cleanup(enc_ctx, auth_ctx, mode); + rspamd_cryptobox_cleanup(enc_ctx, auth_ctx); } gboolean rspamd_cryptobox_decrypt_nm_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, const rspamd_nm_t nm, - const rspamd_mac_t sig, enum rspamd_cryptobox_mode mode) + const rspamd_mac_t sig) { gsize r = 0; gboolean ret = TRUE; void *enc_ctx, *auth_ctx; - enc_ctx = g_alloca(rspamd_cryptobox_encrypt_ctx_len(mode)); - auth_ctx = g_alloca(rspamd_cryptobox_auth_ctx_len(mode)); + enc_ctx = g_alloca(sizeof(chacha_state) + CRYPTOBOX_ALIGNMENT); + auth_ctx = g_alloca(sizeof(crypto_onetimeauth_state) + RSPAMD_ALIGNOF(crypto_onetimeauth_state)); - enc_ctx = rspamd_cryptobox_decrypt_init(enc_ctx, nonce, nm, mode); - auth_ctx = rspamd_cryptobox_auth_verify_init(auth_ctx, enc_ctx, mode); + enc_ctx = rspamd_cryptobox_decrypt_init(enc_ctx, nonce, nm); + auth_ctx = rspamd_cryptobox_auth_verify_init(auth_ctx, enc_ctx); - rspamd_cryptobox_auth_verify_update(auth_ctx, data, len, mode); + rspamd_cryptobox_auth_verify_update(auth_ctx, data, len); - if (!rspamd_cryptobox_auth_verify_final(auth_ctx, sig, mode)) { + if (!rspamd_cryptobox_auth_verify_final(auth_ctx, sig)) { ret = FALSE; } else { - rspamd_cryptobox_decrypt_update(enc_ctx, data, len, data, &r, mode); - ret = rspamd_cryptobox_decrypt_final(enc_ctx, data + r, len - r, mode); + rspamd_cryptobox_decrypt_update(enc_ctx, data, len, data, &r); + ret = rspamd_cryptobox_decrypt_final(enc_ctx, data + r, len - r); } - rspamd_cryptobox_cleanup(enc_ctx, auth_ctx, mode); + rspamd_cryptobox_cleanup(enc_ctx, auth_ctx); return ret; } @@ -1238,14 +788,13 @@ gboolean rspamd_cryptobox_decrypt_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, const rspamd_pk_t pk, const rspamd_sk_t sk, - const rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) + const rspamd_mac_t sig) { unsigned char nm[rspamd_cryptobox_MAX_NMBYTES]; gboolean ret; - rspamd_cryptobox_nm(nm, pk, sk, mode); - ret = rspamd_cryptobox_decrypt_nm_inplace(data, len, nonce, nm, sig, mode); + rspamd_cryptobox_nm(nm, pk, sk); + ret = rspamd_cryptobox_decrypt_nm_inplace(data, len, nonce, nm, sig); rspamd_explicit_memzero(nm, sizeof(nm)); @@ -1255,13 +804,12 @@ rspamd_cryptobox_decrypt_inplace(unsigned char *data, gsize len, void rspamd_cryptobox_encrypt_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, const rspamd_pk_t pk, const rspamd_sk_t sk, - rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) + rspamd_mac_t sig) { unsigned char nm[rspamd_cryptobox_MAX_NMBYTES]; - rspamd_cryptobox_nm(nm, pk, sk, mode); - rspamd_cryptobox_encrypt_nm_inplace(data, len, nonce, nm, sig, mode); + rspamd_cryptobox_nm(nm, pk, sk); + rspamd_cryptobox_encrypt_nm_inplace(data, len, nonce, nm, sig); rspamd_explicit_memzero(nm, sizeof(nm)); } @@ -1269,13 +817,12 @@ void rspamd_cryptobox_encryptv_inplace(struct rspamd_cryptobox_segment *segments gsize cnt, const rspamd_nonce_t nonce, const rspamd_pk_t pk, const rspamd_sk_t sk, - rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode) + rspamd_mac_t sig) { unsigned char nm[rspamd_cryptobox_MAX_NMBYTES]; - rspamd_cryptobox_nm(nm, pk, sk, mode); - rspamd_cryptobox_encryptv_nm_inplace(segments, cnt, nonce, nm, sig, mode); + rspamd_cryptobox_nm(nm, pk, sk); + rspamd_cryptobox_encryptv_nm_inplace(segments, cnt, nonce, nm, sig); rspamd_explicit_memzero(nm, sizeof(nm)); } @@ -1288,9 +835,9 @@ void rspamd_cryptobox_siphash(unsigned char *out, const unsigned char *in, } /* - * Password-Based Key Derivation Function 2 (PKCS #5 v2.0). - * Code based on IEEE Std 802.11-2007, Annex H.4.2. - */ +* Password-Based Key Derivation Function 2 (PKCS #5 v2.0). +* Code based on IEEE Std 802.11-2007, Annex H.4.2. +*/ static gboolean rspamd_cryptobox_pbkdf2(const char *pass, gsize pass_len, const uint8_t *salt, gsize salt_len, uint8_t *key, gsize key_len, @@ -1327,9 +874,9 @@ rspamd_cryptobox_pbkdf2(const char *pass, gsize pass_len, uint8_t k[crypto_generichash_blake2b_BYTES_MAX]; /* - * We use additional blake2 iteration to store large key - * XXX: it is not compatible with the original implementation but safe - */ + * We use additional blake2 iteration to store large key + * XXX: it is not compatible with the original implementation but safe + */ crypto_generichash_blake2b(k, sizeof(k), pass, pass_len, NULL, 0); crypto_generichash_blake2b(d1, sizeof(d1), asalt, salt_len + 4, @@ -1347,9 +894,9 @@ rspamd_cryptobox_pbkdf2(const char *pass, gsize pass_len, uint8_t k[crypto_generichash_blake2b_BYTES_MAX]; /* - * We use additional blake2 iteration to store large key - * XXX: it is not compatible with the original implementation but safe - */ + * We use additional blake2 iteration to store large key + * XXX: it is not compatible with the original implementation but safe + */ crypto_generichash_blake2b(k, sizeof(k), pass, pass_len, NULL, 0); crypto_generichash_blake2b(d2, sizeof(d2), d1, sizeof(d1), @@ -1402,84 +949,6 @@ rspamd_cryptobox_pbkdf(const char *pass, gsize pass_len, return ret; } -unsigned int rspamd_cryptobox_pk_bytes(enum rspamd_cryptobox_mode mode) -{ - if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return 32; - } - else { - return 65; - } -} - -unsigned int rspamd_cryptobox_pk_sig_bytes(enum rspamd_cryptobox_mode mode) -{ - if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return 32; - } - else { - return 65; - } -} - -unsigned int rspamd_cryptobox_nonce_bytes(enum rspamd_cryptobox_mode mode) -{ - if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return 24; - } - else { - return 16; - } -} - - -unsigned int rspamd_cryptobox_sk_bytes(enum rspamd_cryptobox_mode mode) -{ - return 32; -} - -unsigned int rspamd_cryptobox_sk_sig_bytes(enum rspamd_cryptobox_mode mode) -{ - if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return 64; - } - else { - return 32; - } -} - -unsigned int rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode) -{ - static unsigned int ssl_keylen; - - if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) { - return 64; - } - else { -#ifndef HAVE_USABLE_OPENSSL - g_assert(0); -#else - if (ssl_keylen == 0) { - EC_KEY *lk; - lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID); - ssl_keylen = ECDSA_size(lk); - EC_KEY_free(lk); - } -#endif - return ssl_keylen; - } -} - -unsigned int rspamd_cryptobox_nm_bytes(enum rspamd_cryptobox_mode mode) -{ - return 32; -} - -unsigned int rspamd_cryptobox_mac_bytes(enum rspamd_cryptobox_mode mode) -{ - return 16; -} - void rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t *p, const unsigned char *key, gsize keylen) { crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p, @@ -1489,8 +958,8 @@ void rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t *p, const unsigned } /** - * Update hash with data portion - */ +* Update hash with data portion +*/ void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *p, const unsigned char *data, gsize len) { crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p, @@ -1499,8 +968,8 @@ void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *p, const unsign } /** - * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length - */ +* Output hash to the buffer of rspamd_cryptobox_HASHBYTES length +*/ void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *p, unsigned char *out) { crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p, @@ -1509,8 +978,8 @@ void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *p, unsigned char } /** - * One in all function - */ +* One in all function +*/ void rspamd_cryptobox_hash(unsigned char *out, const unsigned char *data, gsize len, @@ -1729,8 +1198,8 @@ rspamd_cryptobox_fast_hash_final(rspamd_cryptobox_fast_hash_state_t *st) } /** - * One in all function - */ +* One in all function +*/ static inline uint64_t rspamd_cryptobox_fast_hash_machdep(const void *data, gsize len, uint64_t seed) diff --git a/src/libcryptobox/cryptobox.h b/src/libcryptobox/cryptobox.h index 8382c8f68..afe9c4f9a 100644 --- a/src/libcryptobox/cryptobox.h +++ b/src/libcryptobox/cryptobox.h @@ -13,11 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #ifndef CRYPTOBOX_H_ #define CRYPTOBOX_H_ #include "config.h" +#ifdef HAVE_OPENSSL +#include <openssl/evp.h> +#endif + #include <sodium.h> #ifdef __cplusplus @@ -35,18 +40,18 @@ struct rspamd_cryptobox_segment { #define RSPAMD_HAS_TARGET_ATTR 1 #endif -#define rspamd_cryptobox_MAX_NONCEBYTES 24 -#define rspamd_cryptobox_MAX_PKBYTES 65 -#define rspamd_cryptobox_MAX_SKBYTES 32 -#define rspamd_cryptobox_MAX_MACBYTES 16 -#define rspamd_cryptobox_MAX_NMBYTES 32 +#define rspamd_cryptobox_MAX_NONCEBYTES crypto_box_NONCEBYTES +#define rspamd_cryptobox_MAX_PKBYTES crypto_box_PUBLICKEYBYTES +#define rspamd_cryptobox_MAX_SKBYTES crypto_box_SECRETKEYBYTES +#define rspamd_cryptobox_MAX_MACBYTES crypto_box_MACBYTES +#define rspamd_cryptobox_MAX_NMBYTES crypto_box_BEFORENMBYTES #define rspamd_cryptobox_SIPKEYBYTES 16 #define rspamd_cryptobox_HASHBYTES 64 #define rspamd_cryptobox_HASHKEYBYTES 64 #define rspamd_cryptobox_HASHSTATEBYTES sizeof(crypto_generichash_blake2b_state) + 64 -#define rspamd_cryptobox_MAX_SIGSKBYTES 64 -#define rspamd_cryptobox_MAX_SIGPKBYTES 32 -#define rspamd_cryptobox_MAX_SIGBYTES 72 +#define rspamd_cryptobox_MAX_SIGSKBYTES crypto_sign_SECRETKEYBYTES +#define rspamd_cryptobox_MAX_SIGPKBYTES crypto_sign_PUBLICKEYBYTES +#define rspamd_cryptobox_MAX_SIGBYTES crypto_sign_BYTES #define CPUID_AVX2 0x1 #define CPUID_AVX 0x2 @@ -67,10 +72,6 @@ typedef unsigned char rspamd_signature_t[rspamd_cryptobox_MAX_SIGBYTES]; typedef unsigned char rspamd_sig_pk_t[rspamd_cryptobox_MAX_SIGPKBYTES]; typedef unsigned char rspamd_sig_sk_t[rspamd_cryptobox_MAX_SIGSKBYTES]; -enum rspamd_cryptobox_mode { - RSPAMD_CRYPTOBOX_MODE_25519 = 0, - RSPAMD_CRYPTOBOX_MODE_NIST -}; struct rspamd_cryptobox_library_ctx { char *cpu_extensions; @@ -80,172 +81,190 @@ struct rspamd_cryptobox_library_ctx { }; /** - * Init cryptobox library - */ +* Init cryptobox library +*/ struct rspamd_cryptobox_library_ctx *rspamd_cryptobox_init(void); void rspamd_cryptobox_deinit(struct rspamd_cryptobox_library_ctx *); /** - * Generate new keypair - * @param pk public key buffer - * @param sk secret key buffer - */ -void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk, - enum rspamd_cryptobox_mode mode); +* Generate new keypair +* @param pk public key buffer +* @param sk secret key buffer +*/ +void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk); /** - * Generate new keypair for signing - * @param pk public key buffer - * @param sk secret key buffer - */ -void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk, - enum rspamd_cryptobox_mode mode); +* Generate new keypair for signing +* @param pk public key buffer +* @param sk secret key buffer +*/ +void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk); /** - * Encrypt data inplace adding signature to sig afterwards - * @param data input buffer - * @param pk remote pubkey - * @param sk local secret key - * @param sig output signature - */ +* Encrypt data inplace adding signature to sig afterwards +* @param data input buffer +* @param pk remote pubkey +* @param sk local secret key +* @param sig output signature +*/ void rspamd_cryptobox_encrypt_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, - const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode); + const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig); /** - * Encrypt segments of data inplace adding signature to sig afterwards - * @param segments segments of data - * @param cnt count of segments - * @param pk remote pubkey - * @param sk local secret key - * @param sig output signature - */ +* Encrypt segments of data inplace adding signature to sig afterwards +* @param segments segments of data +* @param cnt count of segments +* @param pk remote pubkey +* @param sk local secret key +* @param sig output signature +*/ void rspamd_cryptobox_encryptv_inplace(struct rspamd_cryptobox_segment *segments, gsize cnt, const rspamd_nonce_t nonce, - const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode); + const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig); /** - * Decrypt and verify data chunk inplace - * @param data data to decrypt - * @param len length of data - * @param pk remote pubkey - * @param sk local privkey - * @param sig signature input - * @return TRUE if input has been verified successfully - */ +* Decrypt and verify data chunk inplace +* @param data data to decrypt +* @param len length of data +* @param pk remote pubkey +* @param sk local privkey +* @param sig signature input +* @return TRUE if input has been verified successfully +*/ gboolean rspamd_cryptobox_decrypt_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, - const rspamd_pk_t pk, const rspamd_sk_t sk, const rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode); + const rspamd_pk_t pk, const rspamd_sk_t sk, const rspamd_mac_t sig); /** - * Encrypt segments of data inplace adding signature to sig afterwards - * @param segments segments of data - * @param cnt count of segments - * @param pk remote pubkey - * @param sk local secret key - * @param sig output signature - */ +* Encrypt segments of data inplace adding signature to sig afterwards +* @param segments segments of data +* @param cnt count of segments +* @param pk remote pubkey +* @param sk local secret key +* @param sig output signature +*/ void rspamd_cryptobox_encrypt_nm_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, - const rspamd_nm_t nm, rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode); + const rspamd_nm_t nm, rspamd_mac_t sig); /** - * Encrypt segments of data inplace adding signature to sig afterwards - * @param segments segments of data - * @param cnt count of segments - * @param pk remote pubkey - * @param sk local secret key - * @param sig output signature - */ +* Encrypt segments of data inplace adding signature to sig afterwards +* @param segments segments of data +* @param cnt count of segments +* @param pk remote pubkey +* @param sk local secret key +* @param sig output signature +*/ void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segments, gsize cnt, const rspamd_nonce_t nonce, - const rspamd_nm_t nm, rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode); + const rspamd_nm_t nm, rspamd_mac_t sig); /** - * Decrypt and verify data chunk inplace - * @param data data to decrypt - * @param len length of data - * @param pk remote pubkey - * @param sk local privkey - * @param sig signature input - * @return TRUE if input has been verified successfully - */ +* Decrypt and verify data chunk inplace +* @param data data to decrypt +* @param len length of data +* @param pk remote pubkey +* @param sk local privkey +* @param sig signature input +* @return TRUE if input has been verified successfully +*/ gboolean rspamd_cryptobox_decrypt_nm_inplace(unsigned char *data, gsize len, const rspamd_nonce_t nonce, - const rspamd_nm_t nm, const rspamd_mac_t sig, - enum rspamd_cryptobox_mode mode); + const rspamd_nm_t nm, const rspamd_mac_t sig); /** - * Generate shared secret from local sk and remote pk - * @param nm shared secret - * @param pk remote pubkey - * @param sk local privkey - */ -void rspamd_cryptobox_nm(rspamd_nm_t nm, const rspamd_pk_t pk, - const rspamd_sk_t sk, enum rspamd_cryptobox_mode mode); +* Generate shared secret from local sk and remote pk +* @param nm shared secret +* @param pk remote pubkey +* @param sk local privkey +*/ +void rspamd_cryptobox_nm(rspamd_nm_t nm, const rspamd_pk_t pk, const rspamd_sk_t sk); /** - * Create digital signature for the specified message and place result in `sig` - * @param sig signature target - * @param siglen_p pointer to signature length (might be NULL) - * @param m input message - * @param mlen input length - * @param sk secret key - */ +* Create digital signature for the specified message and place result in `sig` +* @param sig signature target +* @param siglen_p pointer to signature length (might be NULL) +* @param m input message +* @param mlen input length +* @param sk secret key +*/ void rspamd_cryptobox_sign(unsigned char *sig, unsigned long long *siglen_p, const unsigned char *m, gsize mlen, - const rspamd_sk_t sk, - enum rspamd_cryptobox_mode mode); + const rspamd_sig_sk_t sk); /** - * Verifies digital signature for the specified message using the specified - * pubkey - * @param sig signature source - * @param m input message - * @param mlen message length - * @param pk public key for verification - * @return true if signature is valid, false otherwise - */ +* Verifies digital signature for the specified message using the specified +* pubkey +* @param sig signature source +* @param m input message +* @param mlen message length +* @param pk public key for verification +* @return true if signature is valid, false otherwise +*/ bool rspamd_cryptobox_verify(const unsigned char *sig, gsize siglen, const unsigned char *m, gsize mlen, - const rspamd_pk_t pk, - enum rspamd_cryptobox_mode mode); + const rspamd_sig_pk_t pk); +#ifdef HAVE_OPENSSL /** - * Securely clear the buffer specified - * @param buf buffer to zero - * @param buflen length of buffer + * Verifies digital signature for specified raw digest with specified pubkey + * @param nid signing algorithm nid + * @param sig signature source + * @param digest raw digest + * @param pub_key public key for verification + * @return true if signature is valid, false otherwise */ +bool rspamd_cryptobox_verify_evp_ed25519(int nid, + const unsigned char *sig, + gsize siglen, + const unsigned char *digest, + gsize dlen, + EVP_PKEY *pub_key); +bool rspamd_cryptobox_verify_evp_ecdsa(int nid, + const unsigned char *sig, + gsize siglen, + const unsigned char *digest, + gsize dlen, + EVP_PKEY *pub_key); +bool rspamd_cryptobox_verify_evp_rsa(int nid, + const unsigned char *sig, + gsize siglen, + const unsigned char *digest, + gsize dlen, + EVP_PKEY *pub_key); +#endif + +/** +* Securely clear the buffer specified +* @param buf buffer to zero +* @param buflen length of buffer +*/ #define rspamd_explicit_memzero sodium_memzero /** - * Constant time memcmp - * @param b1_ - * @param b2_ - * @param len - * @return - */ +* Constant time memcmp +* @param b1_ +* @param b2_ +* @param len +* @return +*/ #define rspamd_cryptobox_memcmp sodium_memcmp /** - * Calculates siphash-2-4 for a message - * @param out (8 bytes output) - * @param in - * @param inlen - * @param k key (must be 16 bytes) - */ +* Calculates siphash-2-4 for a message +* @param out (8 bytes output) +* @param in +* @param inlen +* @param k key (must be 16 bytes) +*/ void rspamd_cryptobox_siphash(unsigned char *out, const unsigned char *in, unsigned long long inlen, const rspamd_sipkey_t k); @@ -257,16 +276,16 @@ enum rspamd_cryptobox_pbkdf_type { /** - * Derive key from password using the specified algorithm - * @param pass input password - * @param pass_len length of the password - * @param salt input salt - * @param salt_len length of salt - * @param key output key - * @param key_len size of the key - * @param complexity empiric number of complexity (rounds for pbkdf2 and garlic for catena) - * @return TRUE in case of success and FALSE if failed - */ +* Derive key from password using the specified algorithm +* @param pass input password +* @param pass_len length of the password +* @param salt input salt +* @param salt_len length of salt +* @param key output key +* @param key_len size of the key +* @param complexity empiric number of complexity (rounds for pbkdf2 and garlic for catena) +* @return TRUE in case of success and FALSE if failed +*/ gboolean rspamd_cryptobox_pbkdf(const char *pass, gsize pass_len, const uint8_t *salt, gsize salt_len, uint8_t *key, gsize key_len, @@ -274,71 +293,31 @@ gboolean rspamd_cryptobox_pbkdf(const char *pass, gsize pass_len, enum rspamd_cryptobox_pbkdf_type type); -/** - * Real size of rspamd cryptobox public key - */ -unsigned int rspamd_cryptobox_pk_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of rspamd cryptobox signing public key - */ -unsigned int rspamd_cryptobox_pk_sig_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of crypto nonce - */ -unsigned int rspamd_cryptobox_nonce_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of rspamd cryptobox secret key - */ -unsigned int rspamd_cryptobox_sk_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of rspamd cryptobox signing secret key - */ -unsigned int rspamd_cryptobox_sk_sig_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of rspamd cryptobox shared key - */ -unsigned int rspamd_cryptobox_nm_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of rspamd cryptobox MAC signature - */ -unsigned int rspamd_cryptobox_mac_bytes(enum rspamd_cryptobox_mode mode); - -/** - * Real size of rspamd cryptobox digital signature - */ -unsigned int rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode); - /* Hash IUF interface */ typedef crypto_generichash_blake2b_state rspamd_cryptobox_hash_state_t; /** - * Init cryptobox hash state using key if needed, `st` must point to the buffer - * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then - * non-keyed hash is generated - */ +* Init cryptobox hash state using key if needed, `st` must point to the buffer +* with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then +* non-keyed hash is generated +*/ void rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t *st, const unsigned char *key, gsize keylen); /** - * Update hash with data portion - */ +* Update hash with data portion +*/ void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *st, const unsigned char *data, gsize len); /** - * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length - */ +* Output hash to the buffer of rspamd_cryptobox_HASHBYTES length +*/ void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *st, unsigned char *out); /** - * One in all function - */ +* One in all function +*/ void rspamd_cryptobox_hash(unsigned char *out, const unsigned char *data, gsize len, @@ -363,71 +342,71 @@ typedef struct CRYPTO_ALIGN(64) rspamd_cryptobox_fast_hash_state_s { /** - * Creates a new cryptobox state properly aligned - * @return - */ +* Creates a new cryptobox state properly aligned +* @return +*/ rspamd_cryptobox_fast_hash_state_t *rspamd_cryptobox_fast_hash_new(void); void rspamd_cryptobox_fast_hash_free(rspamd_cryptobox_fast_hash_state_t *st); /** - * Init cryptobox hash state using key if needed, `st` must point to the buffer - * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then - * non-keyed hash is generated - */ +* Init cryptobox hash state using key if needed, `st` must point to the buffer +* with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then +* non-keyed hash is generated +*/ void rspamd_cryptobox_fast_hash_init(rspamd_cryptobox_fast_hash_state_t *st, uint64_t seed); /** - * Init cryptobox hash state using key if needed, `st` must point to the buffer - * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then - * non-keyed hash is generated - */ +* Init cryptobox hash state using key if needed, `st` must point to the buffer +* with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then +* non-keyed hash is generated +*/ void rspamd_cryptobox_fast_hash_init_specific(rspamd_cryptobox_fast_hash_state_t *st, enum rspamd_cryptobox_fast_hash_type type, uint64_t seed); /** - * Update hash with data portion - */ +* Update hash with data portion +*/ void rspamd_cryptobox_fast_hash_update(rspamd_cryptobox_fast_hash_state_t *st, const void *data, gsize len); /** - * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length - */ +* Output hash to the buffer of rspamd_cryptobox_HASHBYTES length +*/ uint64_t rspamd_cryptobox_fast_hash_final(rspamd_cryptobox_fast_hash_state_t *st); /** - * One in all function - */ +* One in all function +*/ uint64_t rspamd_cryptobox_fast_hash(const void *data, gsize len, uint64_t seed); /** - * Platform independent version - */ +* Platform independent version +*/ uint64_t rspamd_cryptobox_fast_hash_specific( enum rspamd_cryptobox_fast_hash_type type, const void *data, gsize len, uint64_t seed); /** - * Decode base64 using platform optimized code - * @param in - * @param inlen - * @param out - * @param outlen - * @return - */ +* Decode base64 using platform optimized code +* @param in +* @param inlen +* @param out +* @param outlen +* @return +*/ gboolean rspamd_cryptobox_base64_decode(const char *in, gsize inlen, unsigned char *out, gsize *outlen); /** - * Returns TRUE if data looks like a valid base64 string - * @param in - * @param inlen - * @return - */ +* Returns TRUE if data looks like a valid base64 string +* @param in +* @param inlen +* @return +*/ gboolean rspamd_cryptobox_base64_is_valid(const char *in, gsize inlen); #ifdef __cplusplus diff --git a/src/libcryptobox/keypair.c b/src/libcryptobox/keypair.c index 02070bb46..d3f81ee2d 100644 --- a/src/libcryptobox/keypair.c +++ b/src/libcryptobox/keypair.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -38,29 +38,14 @@ rspamd_cryptobox_keypair_sk(struct rspamd_cryptobox_keypair *kp, { g_assert(kp != NULL); - if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) { - if (kp->type == RSPAMD_KEYPAIR_KEX) { - *len = 32; - return RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp)->sk; - } - else { - *len = 64; - return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(kp)->sk; - } + if (kp->type == RSPAMD_KEYPAIR_KEX) { + *len = 32; + return RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp)->sk; } else { - if (kp->type == RSPAMD_KEYPAIR_KEX) { - *len = 32; - return RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp)->sk; - } - else { - *len = 32; - return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_NIST(kp)->sk; - } + *len = 64; + return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(kp)->sk; } - - /* Not reached */ - return NULL; } static void * @@ -69,29 +54,14 @@ rspamd_cryptobox_keypair_pk(struct rspamd_cryptobox_keypair *kp, { g_assert(kp != NULL); - if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) { - if (kp->type == RSPAMD_KEYPAIR_KEX) { - *len = 32; - return RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp)->pk; - } - else { - *len = 32; - return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(kp)->pk; - } + if (kp->type == RSPAMD_KEYPAIR_KEX) { + *len = 32; + return RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp)->pk; } else { - if (kp->type == RSPAMD_KEYPAIR_KEX) { - *len = 65; - return RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp)->pk; - } - else { - *len = 65; - return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_NIST(kp)->pk; - } + *len = 32; + return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(kp)->pk; } - - /* Not reached */ - return NULL; } static void * @@ -100,53 +70,27 @@ rspamd_cryptobox_pubkey_pk(const struct rspamd_cryptobox_pubkey *kp, { g_assert(kp != NULL); - if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) { - if (kp->type == RSPAMD_KEYPAIR_KEX) { - *len = 32; - return RSPAMD_CRYPTOBOX_PUBKEY_25519(kp)->pk; - } - else { - *len = 32; - return RSPAMD_CRYPTOBOX_PUBKEY_SIG_25519(kp)->pk; - } + if (kp->type == RSPAMD_KEYPAIR_KEX) { + *len = 32; + return RSPAMD_CRYPTOBOX_PUBKEY_25519(kp)->pk; } else { - if (kp->type == RSPAMD_KEYPAIR_KEX) { - *len = 65; - return RSPAMD_CRYPTOBOX_PUBKEY_NIST(kp)->pk; - } - else { - *len = 65; - return RSPAMD_CRYPTOBOX_PUBKEY_SIG_NIST(kp)->pk; - } + *len = 32; + return RSPAMD_CRYPTOBOX_PUBKEY_SIG_25519(kp)->pk; } - - /* Not reached */ - return NULL; } static struct rspamd_cryptobox_keypair * -rspamd_cryptobox_keypair_alloc(enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg) +rspamd_cryptobox_keypair_alloc(enum rspamd_cryptobox_keypair_type type) { struct rspamd_cryptobox_keypair *kp; unsigned int size = 0; - if (alg == RSPAMD_CRYPTOBOX_MODE_25519) { - if (type == RSPAMD_KEYPAIR_KEX) { - size = sizeof(struct rspamd_cryptobox_keypair_25519); - } - else { - size = sizeof(struct rspamd_cryptobox_keypair_sig_25519); - } + if (type == RSPAMD_KEYPAIR_KEX) { + size = sizeof(struct rspamd_cryptobox_keypair_25519); } else { - if (type == RSPAMD_KEYPAIR_KEX) { - size = sizeof(struct rspamd_cryptobox_keypair_nist); - } - else { - size = sizeof(struct rspamd_cryptobox_keypair_sig_nist); - } + size = sizeof(struct rspamd_cryptobox_keypair_sig_25519); } g_assert(size >= sizeof(*kp)); @@ -161,27 +105,17 @@ rspamd_cryptobox_keypair_alloc(enum rspamd_cryptobox_keypair_type type, } static struct rspamd_cryptobox_pubkey * -rspamd_cryptobox_pubkey_alloc(enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg) +rspamd_cryptobox_pubkey_alloc(enum rspamd_cryptobox_keypair_type type) { struct rspamd_cryptobox_pubkey *pk; unsigned int size = 0; - if (alg == RSPAMD_CRYPTOBOX_MODE_25519) { - if (type == RSPAMD_KEYPAIR_KEX) { - size = sizeof(struct rspamd_cryptobox_pubkey_25519); - } - else { - size = sizeof(struct rspamd_cryptobox_pubkey_sig_25519); - } + + if (type == RSPAMD_KEYPAIR_KEX) { + size = sizeof(struct rspamd_cryptobox_pubkey_25519); } else { - if (type == RSPAMD_KEYPAIR_KEX) { - size = sizeof(struct rspamd_cryptobox_pubkey_nist); - } - else { - size = sizeof(struct rspamd_cryptobox_pubkey_sig_nist); - } + size = sizeof(struct rspamd_cryptobox_pubkey_sig_25519); } g_assert(size >= sizeof(*pk)); @@ -230,25 +164,23 @@ void rspamd_cryptobox_pubkey_dtor(struct rspamd_cryptobox_pubkey *p) } struct rspamd_cryptobox_keypair * -rspamd_keypair_new(enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg) +rspamd_keypair_new(enum rspamd_cryptobox_keypair_type type) { struct rspamd_cryptobox_keypair *kp; void *pk, *sk; unsigned int size; - kp = rspamd_cryptobox_keypair_alloc(type, alg); - kp->alg = alg; + kp = rspamd_cryptobox_keypair_alloc(type); kp->type = type; sk = rspamd_cryptobox_keypair_sk(kp, &size); pk = rspamd_cryptobox_keypair_pk(kp, &size); if (type == RSPAMD_KEYPAIR_KEX) { - rspamd_cryptobox_keypair(pk, sk, alg); + rspamd_cryptobox_keypair(pk, sk); } else { - rspamd_cryptobox_keypair_sig(pk, sk, alg); + rspamd_cryptobox_keypair_sig(pk, sk); } rspamd_cryptobox_hash(kp->id, pk, size, NULL, 0); @@ -302,27 +234,10 @@ rspamd_pubkey_type(struct rspamd_cryptobox_pubkey *p) } -enum rspamd_cryptobox_mode -rspamd_keypair_alg(struct rspamd_cryptobox_keypair *kp) -{ - g_assert(kp != NULL); - - return kp->alg; -} - -enum rspamd_cryptobox_mode -rspamd_pubkey_alg(struct rspamd_cryptobox_pubkey *p) -{ - g_assert(p != NULL); - - return p->alg; -} - struct rspamd_cryptobox_pubkey * rspamd_pubkey_from_base32(const char *b32, gsize len, - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg) + enum rspamd_cryptobox_keypair_type type) { unsigned char *decoded; gsize dlen, expected_len; @@ -342,16 +257,15 @@ rspamd_pubkey_from_base32(const char *b32, return NULL; } - expected_len = (type == RSPAMD_KEYPAIR_KEX) ? rspamd_cryptobox_pk_bytes(alg) : rspamd_cryptobox_pk_sig_bytes(alg); + expected_len = (type == RSPAMD_KEYPAIR_KEX) ? crypto_box_PUBLICKEYBYTES : crypto_sign_PUBLICKEYBYTES; if (dlen != expected_len) { g_free(decoded); return NULL; } - pk = rspamd_cryptobox_pubkey_alloc(type, alg); + pk = rspamd_cryptobox_pubkey_alloc(type); REF_INIT_RETAIN(pk, rspamd_cryptobox_pubkey_dtor); - pk->alg = alg; pk->type = type; pk_data = rspamd_cryptobox_pubkey_pk(pk, &pklen); @@ -365,8 +279,7 @@ rspamd_pubkey_from_base32(const char *b32, struct rspamd_cryptobox_pubkey * rspamd_pubkey_from_hex(const char *hex, gsize len, - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg) + enum rspamd_cryptobox_keypair_type type) { unsigned char *decoded; gsize dlen, expected_len; @@ -388,16 +301,15 @@ rspamd_pubkey_from_hex(const char *hex, return NULL; } - expected_len = (type == RSPAMD_KEYPAIR_KEX) ? rspamd_cryptobox_pk_bytes(alg) : rspamd_cryptobox_pk_sig_bytes(alg); + expected_len = (type == RSPAMD_KEYPAIR_KEX) ? crypto_box_PUBLICKEYBYTES : crypto_sign_PUBLICKEYBYTES; if (dlen != expected_len) { g_free(decoded); return NULL; } - pk = rspamd_cryptobox_pubkey_alloc(type, alg); + pk = rspamd_cryptobox_pubkey_alloc(type); REF_INIT_RETAIN(pk, rspamd_cryptobox_pubkey_dtor); - pk->alg = alg; pk->type = type; pk_data = rspamd_cryptobox_pubkey_pk(pk, &pklen); @@ -411,25 +323,20 @@ rspamd_pubkey_from_hex(const char *hex, struct rspamd_cryptobox_pubkey * rspamd_pubkey_from_bin(const unsigned char *raw, gsize len, - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg) + enum rspamd_cryptobox_keypair_type type) { - gsize expected_len; unsigned int pklen; struct rspamd_cryptobox_pubkey *pk; unsigned char *pk_data; g_assert(raw != NULL && len > 0); - expected_len = (type == RSPAMD_KEYPAIR_KEX) ? rspamd_cryptobox_pk_bytes(alg) : rspamd_cryptobox_pk_sig_bytes(alg); - - if (len != expected_len) { + if (len != crypto_box_PUBLICKEYBYTES) { return NULL; } - pk = rspamd_cryptobox_pubkey_alloc(type, alg); + pk = rspamd_cryptobox_pubkey_alloc(type); REF_INIT_RETAIN(pk, rspamd_cryptobox_pubkey_dtor); - pk->alg = alg; pk->type = type; pk_data = rspamd_cryptobox_pubkey_pk(pk, &pklen); @@ -463,7 +370,6 @@ const unsigned char * rspamd_pubkey_calculate_nm(struct rspamd_cryptobox_pubkey *p, struct rspamd_cryptobox_keypair *kp) { - g_assert(kp->alg == p->alg); g_assert(kp->type == p->type); g_assert(p->type == RSPAMD_KEYPAIR_KEX); @@ -476,22 +382,12 @@ rspamd_pubkey_calculate_nm(struct rspamd_cryptobox_pubkey *p, REF_INIT_RETAIN(p->nm, rspamd_cryptobox_nm_dtor); } - if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) { - struct rspamd_cryptobox_pubkey_25519 *rk_25519 = - RSPAMD_CRYPTOBOX_PUBKEY_25519(p); - struct rspamd_cryptobox_keypair_25519 *sk_25519 = - RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp); + struct rspamd_cryptobox_pubkey_25519 *rk_25519 = + RSPAMD_CRYPTOBOX_PUBKEY_25519(p); + struct rspamd_cryptobox_keypair_25519 *sk_25519 = + RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp); - rspamd_cryptobox_nm(p->nm->nm, rk_25519->pk, sk_25519->sk, p->alg); - } - else { - struct rspamd_cryptobox_pubkey_nist *rk_nist = - RSPAMD_CRYPTOBOX_PUBKEY_NIST(p); - struct rspamd_cryptobox_keypair_nist *sk_nist = - RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp); - - rspamd_cryptobox_nm(p->nm->nm, rk_nist->pk, sk_nist->sk, p->alg); - } + rspamd_cryptobox_nm(p->nm->nm, rk_25519->pk, sk_25519->sk); return p->nm->nm; } @@ -662,7 +558,6 @@ 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; - enum rspamd_cryptobox_mode mode = RSPAMD_CRYPTOBOX_MODE_25519; gboolean is_hex = FALSE; struct rspamd_cryptobox_keypair *kp; unsigned int len; @@ -705,19 +600,6 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) /* TODO: handle errors */ } - elt = ucl_object_lookup(obj, "algorithm"); - if (elt && ucl_object_type(elt) == UCL_STRING) { - str = ucl_object_tostring(elt); - - if (g_ascii_strcasecmp(str, "curve25519") == 0) { - mode = RSPAMD_CRYPTOBOX_MODE_25519; - } - else if (g_ascii_strcasecmp(str, "nistp256") == 0) { - mode = RSPAMD_CRYPTOBOX_MODE_NIST; - } - /* TODO: handle errors */ - } - elt = ucl_object_lookup(obj, "encoding"); if (elt && ucl_object_type(elt) == UCL_STRING) { str = ucl_object_tostring(elt); @@ -728,9 +610,8 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) /* TODO: handle errors */ } - kp = rspamd_cryptobox_keypair_alloc(type, mode); + kp = rspamd_cryptobox_keypair_alloc(type); kp->type = type; - kp->alg = mode; REF_INIT_RETAIN(kp, rspamd_cryptobox_keypair_dtor); g_assert(kp != NULL); @@ -838,8 +719,7 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp, "encoding", 0, false); ucl_object_insert_key(elt, - ucl_object_fromstring( - kp->alg == RSPAMD_CRYPTOBOX_MODE_NIST ? "nistp256" : "curve25519"), + ucl_object_fromstring("curve25519"), "algorithm", 0, false); ucl_object_insert_key(elt, @@ -873,9 +753,9 @@ rspamd_keypair_decrypt(struct rspamd_cryptobox_keypair *kp, return FALSE; } - if (inlen < sizeof(encrypted_magic) + rspamd_cryptobox_pk_bytes(kp->alg) + - rspamd_cryptobox_mac_bytes(kp->alg) + - rspamd_cryptobox_nonce_bytes(kp->alg)) { + if (inlen < sizeof(encrypted_magic) + crypto_box_publickeybytes() + + crypto_box_macbytes() + + crypto_box_noncebytes()) { g_set_error(err, rspamd_keypair_quark(), E2BIG, "invalid size: too small"); return FALSE; @@ -890,9 +770,9 @@ rspamd_keypair_decrypt(struct rspamd_cryptobox_keypair *kp, /* Set pointers */ pubkey = in + sizeof(encrypted_magic); - mac = pubkey + rspamd_cryptobox_pk_bytes(kp->alg); - nonce = mac + rspamd_cryptobox_mac_bytes(kp->alg); - data = nonce + rspamd_cryptobox_nonce_bytes(kp->alg); + mac = pubkey + crypto_box_publickeybytes(); + nonce = mac + crypto_box_macbytes(); + data = nonce + crypto_box_noncebytes(); if (data - in >= inlen) { g_set_error(err, rspamd_keypair_quark(), E2BIG, "invalid size: too small"); @@ -908,7 +788,7 @@ rspamd_keypair_decrypt(struct rspamd_cryptobox_keypair *kp, if (!rspamd_cryptobox_decrypt_inplace(*out, inlen, nonce, pubkey, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL), - mac, kp->alg)) { + mac)) { g_set_error(err, rspamd_keypair_quark(), EPERM, "verification failed"); g_free(*out); @@ -942,26 +822,26 @@ rspamd_keypair_encrypt(struct rspamd_cryptobox_keypair *kp, return FALSE; } - local = rspamd_keypair_new(kp->type, kp->alg); + local = rspamd_keypair_new(kp->type); olen = inlen + sizeof(encrypted_magic) + - rspamd_cryptobox_pk_bytes(kp->alg) + - rspamd_cryptobox_mac_bytes(kp->alg) + - rspamd_cryptobox_nonce_bytes(kp->alg); + crypto_box_publickeybytes() + + crypto_box_macbytes() + + crypto_box_noncebytes(); *out = g_malloc(olen); memcpy(*out, encrypted_magic, sizeof(encrypted_magic)); pubkey = *out + sizeof(encrypted_magic); - mac = pubkey + rspamd_cryptobox_pk_bytes(kp->alg); - nonce = mac + rspamd_cryptobox_mac_bytes(kp->alg); - data = nonce + rspamd_cryptobox_nonce_bytes(kp->alg); + mac = pubkey + crypto_box_publickeybytes(); + nonce = mac + crypto_box_macbytes(); + data = nonce + crypto_box_noncebytes(); - ottery_rand_bytes(nonce, rspamd_cryptobox_nonce_bytes(kp->alg)); + ottery_rand_bytes(nonce, crypto_box_noncebytes()); memcpy(data, in, inlen); - memcpy(pubkey, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_PK, NULL), - rspamd_cryptobox_pk_bytes(kp->alg)); - rspamd_cryptobox_encrypt_inplace(data, inlen, nonce, pubkey, + memcpy(pubkey, rspamd_keypair_component(local, RSPAMD_KEYPAIR_COMPONENT_PK, NULL), + crypto_box_publickeybytes()); + rspamd_cryptobox_encrypt_inplace(data, inlen, nonce, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_PK, NULL), rspamd_keypair_component(local, RSPAMD_KEYPAIR_COMPONENT_SK, NULL), - mac, kp->alg); + mac); rspamd_keypair_unref(local); if (outlen) { @@ -991,26 +871,26 @@ rspamd_pubkey_encrypt(struct rspamd_cryptobox_pubkey *pk, return FALSE; } - local = rspamd_keypair_new(pk->type, pk->alg); + local = rspamd_keypair_new(pk->type); olen = inlen + sizeof(encrypted_magic) + - rspamd_cryptobox_pk_bytes(pk->alg) + - rspamd_cryptobox_mac_bytes(pk->alg) + - rspamd_cryptobox_nonce_bytes(pk->alg); + crypto_box_publickeybytes() + + crypto_box_macbytes() + + crypto_box_noncebytes(); *out = g_malloc(olen); memcpy(*out, encrypted_magic, sizeof(encrypted_magic)); pubkey = *out + sizeof(encrypted_magic); - mac = pubkey + rspamd_cryptobox_pk_bytes(pk->alg); - nonce = mac + rspamd_cryptobox_mac_bytes(pk->alg); - data = nonce + rspamd_cryptobox_nonce_bytes(pk->alg); + mac = pubkey + crypto_box_publickeybytes(); + nonce = mac + crypto_box_macbytes(); + data = nonce + crypto_box_noncebytes(); - ottery_rand_bytes(nonce, rspamd_cryptobox_nonce_bytes(pk->alg)); + ottery_rand_bytes(nonce, crypto_box_noncebytes()); memcpy(data, in, inlen); - memcpy(pubkey, rspamd_pubkey_get_pk(pk, NULL), - rspamd_cryptobox_pk_bytes(pk->alg)); - rspamd_cryptobox_encrypt_inplace(data, inlen, nonce, pubkey, + memcpy(pubkey, rspamd_keypair_component(local, RSPAMD_KEYPAIR_COMPONENT_PK, NULL), + crypto_box_publickeybytes()); + rspamd_cryptobox_encrypt_inplace(data, inlen, nonce, rspamd_pubkey_get_pk(pk, NULL), rspamd_keypair_component(local, RSPAMD_KEYPAIR_COMPONENT_SK, NULL), - mac, pk->alg); + mac); rspamd_keypair_unref(local); if (outlen) { diff --git a/src/libcryptobox/keypair.h b/src/libcryptobox/keypair.h index 849246255..97b46cbf5 100644 --- a/src/libcryptobox/keypair.h +++ b/src/libcryptobox/keypair.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -50,8 +50,7 @@ struct rspamd_cryptobox_pubkey; * @return fresh keypair generated */ struct rspamd_cryptobox_keypair *rspamd_keypair_new( - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg); + enum rspamd_cryptobox_keypair_type type); /** * Increase refcount for the specific keypair @@ -84,8 +83,7 @@ struct rspamd_cryptobox_pubkey *rspamd_pubkey_ref( */ struct rspamd_cryptobox_pubkey *rspamd_pubkey_from_base32(const char *b32, gsize len, - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg); + enum rspamd_cryptobox_keypair_type type); /** * Load pubkey from hex string @@ -96,8 +94,7 @@ struct rspamd_cryptobox_pubkey *rspamd_pubkey_from_base32(const char *b32, */ struct rspamd_cryptobox_pubkey *rspamd_pubkey_from_hex(const char *hex, gsize len, - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg); + enum rspamd_cryptobox_keypair_type type); /** * Load pubkey from raw chunk string @@ -108,8 +105,7 @@ struct rspamd_cryptobox_pubkey *rspamd_pubkey_from_hex(const char *hex, */ struct rspamd_cryptobox_pubkey *rspamd_pubkey_from_bin(const unsigned char *raw, gsize len, - enum rspamd_cryptobox_keypair_type type, - enum rspamd_cryptobox_mode alg); + enum rspamd_cryptobox_keypair_type type); /** @@ -127,18 +123,7 @@ enum rspamd_cryptobox_keypair_type rspamd_keypair_type( /** * Get type of pubkey */ -enum rspamd_cryptobox_keypair_type rspamd_pubkey_type( - struct rspamd_cryptobox_pubkey *p); - -/** - * Get algorithm of keypair - */ -enum rspamd_cryptobox_mode rspamd_keypair_alg(struct rspamd_cryptobox_keypair *kp); - -/** - * Get algorithm of pubkey - */ -enum rspamd_cryptobox_mode rspamd_pubkey_alg(struct rspamd_cryptobox_pubkey *p); +enum rspamd_cryptobox_keypair_type rspamd_pubkey_type(struct rspamd_cryptobox_pubkey *p); /** * Get cached NM for this specific pubkey diff --git a/src/libcryptobox/keypair_private.h b/src/libcryptobox/keypair_private.h index 793231701..2e372777c 100644 --- a/src/libcryptobox/keypair_private.h +++ b/src/libcryptobox/keypair_private.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -38,22 +38,11 @@ struct rspamd_cryptobox_nm { struct rspamd_cryptobox_keypair { unsigned char id[rspamd_cryptobox_HASHBYTES]; enum rspamd_cryptobox_keypair_type type; - enum rspamd_cryptobox_mode alg; ucl_object_t *extensions; ref_entry_t ref; }; /* - * NIST p256 ecdh keypair - */ -#define RSPAMD_CRYPTOBOX_KEYPAIR_NIST(x) ((struct rspamd_cryptobox_keypair_nist *) (x)) -struct rspamd_cryptobox_keypair_nist { - struct rspamd_cryptobox_keypair parent; - unsigned char sk[32]; - unsigned char pk[65]; -}; - -/* * Curve25519 ecdh keypair */ #define RSPAMD_CRYPTOBOX_KEYPAIR_25519(x) ((struct rspamd_cryptobox_keypair_25519 *) (x)) @@ -64,16 +53,6 @@ struct rspamd_cryptobox_keypair_25519 { }; /* - * NIST p256 ecdsa keypair - */ -#define RSPAMD_CRYPTOBOX_KEYPAIR_SIG_NIST(x) ((struct rspamd_cryptobox_keypair_sig_nist *) (x)) -struct rspamd_cryptobox_keypair_sig_nist { - struct rspamd_cryptobox_keypair parent; - unsigned char sk[32]; - unsigned char pk[65]; -}; - -/* * Ed25519 keypair */ #define RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(x) ((struct rspamd_cryptobox_keypair_sig_25519 *) (x)) @@ -90,20 +69,10 @@ struct rspamd_cryptobox_pubkey { unsigned char id[rspamd_cryptobox_HASHBYTES]; struct rspamd_cryptobox_nm *nm; enum rspamd_cryptobox_keypair_type type; - enum rspamd_cryptobox_mode alg; ref_entry_t ref; }; /* - * Public p256 ecdh - */ -#define RSPAMD_CRYPTOBOX_PUBKEY_NIST(x) ((struct rspamd_cryptobox_pubkey_nist *) (x)) -struct rspamd_cryptobox_pubkey_nist { - struct rspamd_cryptobox_pubkey parent; - unsigned char pk[65]; -}; - -/* * Public curve25519 ecdh */ #define RSPAMD_CRYPTOBOX_PUBKEY_25519(x) ((struct rspamd_cryptobox_pubkey_25519 *) (x)) @@ -113,15 +82,6 @@ struct rspamd_cryptobox_pubkey_25519 { }; /* - * Public p256 ecdsa - */ -#define RSPAMD_CRYPTOBOX_PUBKEY_SIG_NIST(x) ((struct rspamd_cryptobox_pubkey_sig_nist *) (x)) -struct rspamd_cryptobox_pubkey_sig_nist { - struct rspamd_cryptobox_pubkey parent; - unsigned char pk[65]; -}; - -/* * Public ed25519 */ #define RSPAMD_CRYPTOBOX_PUBKEY_SIG_25519(x) ((struct rspamd_cryptobox_pubkey_sig_25519 *) (x)) diff --git a/src/libcryptobox/keypairs_cache.c b/src/libcryptobox/keypairs_cache.c index 6003d9923..0b069a64b 100644 --- a/src/libcryptobox/keypairs_cache.c +++ b/src/libcryptobox/keypairs_cache.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -77,7 +77,6 @@ void rspamd_keypair_cache_process(struct rspamd_keypair_cache *c, g_assert(lk != NULL); g_assert(rk != NULL); - g_assert(rk->alg == lk->alg); g_assert(rk->type == lk->type); g_assert(rk->type == RSPAMD_KEYPAIR_KEX); @@ -106,22 +105,12 @@ void rspamd_keypair_cache_process(struct rspamd_keypair_cache *c, rspamd_cryptobox_HASHBYTES); memcpy(&new->nm->sk_id, lk->id, sizeof(uint64_t)); - if (rk->alg == RSPAMD_CRYPTOBOX_MODE_25519) { - struct rspamd_cryptobox_pubkey_25519 *rk_25519 = - RSPAMD_CRYPTOBOX_PUBKEY_25519(rk); - struct rspamd_cryptobox_keypair_25519 *sk_25519 = - RSPAMD_CRYPTOBOX_KEYPAIR_25519(lk); + struct rspamd_cryptobox_pubkey_25519 *rk_25519 = + RSPAMD_CRYPTOBOX_PUBKEY_25519(rk); + struct rspamd_cryptobox_keypair_25519 *sk_25519 = + RSPAMD_CRYPTOBOX_KEYPAIR_25519(lk); - rspamd_cryptobox_nm(new->nm->nm, rk_25519->pk, sk_25519->sk, rk->alg); - } - else { - struct rspamd_cryptobox_pubkey_nist *rk_nist = - RSPAMD_CRYPTOBOX_PUBKEY_NIST(rk); - struct rspamd_cryptobox_keypair_nist *sk_nist = - RSPAMD_CRYPTOBOX_KEYPAIR_NIST(lk); - - rspamd_cryptobox_nm(new->nm->nm, rk_nist->pk, sk_nist->sk, rk->alg); - } + rspamd_cryptobox_nm(new->nm->nm, rk_25519->pk, sk_25519->sk); rspamd_lru_hash_insert(c->hash, new, new, time(NULL), -1); } diff --git a/src/libmime/lang_detection.c b/src/libmime/lang_detection.c index 4796e4834..6e180ea66 100644 --- a/src/libmime/lang_detection.c +++ b/src/libmime/lang_detection.c @@ -1828,7 +1828,7 @@ rspamd_language_detector_detect(struct rspamd_task *task, unsigned int cand_len; enum rspamd_language_category cat; struct rspamd_lang_detector_res *cand; - enum rspamd_language_detected_type r; + enum rspamd_language_detected_type r = rs_detect_none; struct rspamd_frequency_sort_cbdata cbd; /* Check if we have sorted candidates based on frequency */ gboolean frequency_heuristic_applied = FALSE, ret = FALSE, internal_heuristic_applied = FALSE; diff --git a/src/libmime/scan_result.c b/src/libmime/scan_result.c index f15290b95..894ae4f9e 100644 --- a/src/libmime/scan_result.c +++ b/src/libmime/scan_result.c @@ -201,16 +201,34 @@ rspamd_check_group_score(struct rspamd_task *task, double *group_score, double w) { - if (gr != NULL && group_score && gr->max_score > 0.0 && w > 0.0) { - if (*group_score >= gr->max_score && w > 0) { + double group_limit = NAN; + + if (gr != NULL && group_score) { + if ((*group_score + w) >= 0 && !isnan(gr->max_score) && gr->max_score > 0) { + group_limit = gr->max_score; + } + else if ((*group_score + w) < 0 && !isnan(gr->min_score) && gr->min_score < 0) { + group_limit = -gr->min_score; + } + } + + if (gr != NULL && group_limit && !isnan(group_limit)) { + if (fabs(*group_score) >= group_limit && signbit(*group_score) == signbit(w)) { + /* Cannot add more to the group */ msg_info_task("maximum group score %.2f for group %s has been reached," " ignoring symbol %s with weight %.2f", - gr->max_score, + group_limit, gr->name, symbol, w); return NAN; } - else if (*group_score + w > gr->max_score) { - w = gr->max_score - *group_score; + else if (fabs(*group_score + w) > group_limit) { + /* Reduce weight */ + double new_w = signbit(w) ? -group_limit - *group_score : group_limit - *group_score; + msg_info_task("maximum group score %.2f for group %s has been reached," + " reduce weight of symbol %s from %.2f to %.2f", + group_limit, + gr->name, symbol, w, new_w); + w = new_w; } } @@ -393,15 +411,7 @@ insert_metric_result(struct rspamd_task *task, } else if (gr_score) { *gr_score += cur_diff; - - if (cur_diff < diff) { - /* Reduce */ - msg_debug_metric( - "group limit %.2f is reached for %s when inserting symbol %s;" - " reduce score %.2f - %.2f", - *gr_score, gr->name, symbol, diff, cur_diff); - diff = cur_diff; - } + diff = cur_diff; } } } @@ -461,15 +471,7 @@ insert_metric_result(struct rspamd_task *task, } else if (gr_score) { *gr_score += cur_score; - - if (cur_score < final_score) { - /* Reduce */ - msg_debug_metric( - "group limit %.2f is reached for %s when inserting symbol %s;" - " reduce score %.2f - %.2f", - *gr_score, gr->name, symbol, final_score, cur_score); - final_score = cur_score; - } + final_score = cur_score; } } } diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h index a963f952f..f59c6ff89 100644 --- a/src/libserver/cfg_file.h +++ b/src/libserver/cfg_file.h @@ -102,6 +102,7 @@ struct rspamd_symbols_group { char *description; GHashTable *symbols; double max_score; + double min_score; unsigned int flags; }; diff --git a/src/libserver/cfg_rcl.cxx b/src/libserver/cfg_rcl.cxx index 2fe37f18e..79509e12e 100644 --- a/src/libserver/cfg_rcl.cxx +++ b/src/libserver/cfg_rcl.cxx @@ -420,6 +420,18 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, return FALSE; } + if (!std::isnan(gr->max_score) && gr->max_score < 0) { + msg_err_config("group %s has negative max_score which is broken, use min_score if required", gr->name); + + return FALSE; + } + if (!std::isnan(gr->min_score) && gr->min_score > 0) { + msg_err_config("group %s has positive min_score which is broken, use max_score if required", gr->name); + + return FALSE; + } + + if (const auto *elt = ucl_object_lookup(obj, "one_shot"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, @@ -2355,6 +2367,12 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) G_STRUCT_OFFSET(struct rspamd_symbols_group, max_score), 0, "Maximum score that could be reached by this symbols group"); + rspamd_rcl_add_default_handler(sub, + "min_score", + rspamd_rcl_parse_struct_double, + G_STRUCT_OFFSET(struct rspamd_symbols_group, min_score), + 0, + "Maximum negative score that could be reached by this symbols group"); } if (!(skip_sections && g_hash_table_lookup(skip_sections, "worker"))) { @@ -3039,21 +3057,16 @@ rspamd_rcl_parse_struct_pubkey(rspamd_mempool_t *pool, gsize len; const char *str; rspamd_cryptobox_keypair_type keypair_type = RSPAMD_KEYPAIR_KEX; - rspamd_cryptobox_mode keypair_mode = RSPAMD_CRYPTOBOX_MODE_25519; if (pd->flags & RSPAMD_CL_FLAG_SIGNKEY) { keypair_type = RSPAMD_KEYPAIR_SIGN; } - if (pd->flags & RSPAMD_CL_FLAG_NISTKEY) { - keypair_mode = RSPAMD_CRYPTOBOX_MODE_NIST; - } target = (struct rspamd_cryptobox_pubkey **) (((char *) pd->user_struct) + pd->offset); if (obj->type == UCL_STRING) { str = ucl_object_tolstring(obj, &len); - pk = rspamd_pubkey_from_base32(str, len, keypair_type, - keypair_mode); + pk = rspamd_pubkey_from_base32(str, len, keypair_type); if (pk != nullptr) { *target = pk; @@ -3482,7 +3495,7 @@ void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg) lua_pushvalue(L, -2); /* Push the existing config */ - ucl_object_push_lua(L, cfg->cfg_ucl_obj, true); + ucl_object_push_lua_unwrapped(L, cfg->cfg_ucl_obj); if (auto ret = lua_pcall(L, 1, 2, err_idx); ret != 0) { msg_err("call to rspamadm lua script failed (%d): %s", ret, @@ -3492,12 +3505,8 @@ void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg) return; } - if (lua_toboolean(L, -2) && lua_type(L, -1) == LUA_TTABLE) { - ucl_object_t *old_cfg = cfg->cfg_ucl_obj; - + if (lua_toboolean(L, -2) && lua_type(L, -1) == LUA_TUSERDATA) { msg_info_config("configuration has been transformed in Lua"); - cfg->cfg_ucl_obj = ucl_object_lua_import(L, -1); - ucl_object_unref(old_cfg); } /* error function */ @@ -3629,7 +3638,8 @@ rspamd_config_parse_ucl(struct rspamd_config *cfg, auto &cfg_file = cfg_file_maybe.value(); /* Try to load keyfile if available */ - rspamd::util::raii_file::open(fmt::format("{}.key", filename), O_RDONLY).map([&](const auto &keyfile) { + auto keyfile_name = fmt::format("{}.key", filename); + rspamd::util::raii_file::open(keyfile_name, O_RDONLY).map([&](const auto &keyfile) { auto *kp_parser = ucl_parser_new(0); if (ucl_parser_add_fd(kp_parser, keyfile.get_fd())) { auto *kp_obj = ucl_parser_get_object(kp_parser); @@ -3638,8 +3648,8 @@ rspamd_config_parse_ucl(struct rspamd_config *cfg, decrypt_keypair = rspamd_keypair_from_ucl(kp_obj); if (decrypt_keypair == nullptr) { - msg_err_config_forced("cannot load keypair from %s.key: invalid keypair", - filename); + msg_err_config_forced("cannot load keypair from %s: invalid keypair", + keyfile_name.c_str()); } else { /* Add decryption support to UCL */ @@ -3651,8 +3661,8 @@ rspamd_config_parse_ucl(struct rspamd_config *cfg, ucl_object_unref(kp_obj); } else { - msg_err_config_forced("cannot load keypair from %s.key: %s", - filename, ucl_parser_get_error(kp_parser)); + msg_err_config_forced("cannot load keypair from %s: %s", + keyfile_name.c_str(), ucl_parser_get_error(kp_parser)); } ucl_parser_free(kp_parser); }); diff --git a/src/libserver/cfg_rcl.h b/src/libserver/cfg_rcl.h index e33656b72..35b9b931f 100644 --- a/src/libserver/cfg_rcl.h +++ b/src/libserver/cfg_rcl.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Vsevolod Stakhov + * Copyright 2024 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,6 @@ enum rspamd_rcl_flag { RSPAMD_CL_FLAG_STRING_LIST_HASH = 0x1 << 12, RSPAMD_CL_FLAG_MULTIPLE = 0x1 << 13, RSPAMD_CL_FLAG_SIGNKEY = 0x1 << 14, - RSPAMD_CL_FLAG_NISTKEY = 0x1 << 15, }; struct rspamd_rcl_struct_parser { diff --git a/src/libserver/cfg_utils.cxx b/src/libserver/cfg_utils.cxx index f17caa8a5..38adf8390 100644 --- a/src/libserver/cfg_utils.cxx +++ b/src/libserver/cfg_utils.cxx @@ -1053,6 +1053,8 @@ rspamd_config_new_group(struct rspamd_config *cfg, const char *name) rspamd_mempool_add_destructor(cfg->cfg_pool, (rspamd_mempool_destruct_t) g_hash_table_unref, gr->symbols); gr->name = rspamd_mempool_strdup(cfg->cfg_pool, name); + gr->max_score = NAN; + gr->min_score = NAN; if (strcmp(gr->name, "ungrouped") == 0) { gr->flags |= RSPAMD_SYMBOL_GROUP_UNGROUPED; diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index 742e4db8b..a76ed31ab 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -155,12 +155,12 @@ struct rspamd_dkim_key_s { gsize decoded_len; char key_id[RSPAMD_DKIM_KEY_ID_LEN]; union { - RSA *key_rsa; - EC_KEY *key_ecdsa; unsigned char *key_eddsa; - } key; - BIO *key_bio; - EVP_PKEY *key_evp; + struct { + BIO *key_bio; + EVP_PKEY *key_evp; + } key_ssl; + } specific; time_t mtime; unsigned int ttl; enum rspamd_dkim_key_type type; @@ -790,12 +790,12 @@ rspamd_dkim_add_arc_seal_headers(rspamd_mempool_t *pool, } /** - * Create new dkim context from signature - * @param sig message's signature - * @param pool pool to allocate memory from - * @param err pointer to error object - * @return new context or NULL - */ +* Create new dkim context from signature +* @param sig message's signature +* @param pool pool to allocate memory from +* @param err pointer to error object +* @return new context or NULL +*/ rspamd_dkim_context_t * rspamd_create_dkim_context(const char *sig, rspamd_mempool_t *pool, @@ -1097,9 +1097,9 @@ rspamd_create_dkim_context(const char *sig, if (state == DKIM_STATE_ERROR) { /* - * We need to return from here as state machine won't - * do any more steps after p == end - */ + * We need to return from here as state machine won't + * do any more steps after p == end + */ if (err) { msg_info_dkim("dkim parse failed: %e", *err); } @@ -1391,25 +1391,24 @@ rspamd_dkim_make_key(const char *keydata, EVP_MD_CTX_destroy(mdctx); if (key->type == RSPAMD_DKIM_KEY_EDDSA) { - key->key.key_eddsa = key->keydata; + key->specific.key_eddsa = key->keydata; - if (key->decoded_len != rspamd_cryptobox_pk_sig_bytes( - RSPAMD_CRYPTOBOX_MODE_25519)) { + if (key->decoded_len != crypto_sign_publickeybytes()) { g_set_error(err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL, - "DKIM key is has invalid length %d for eddsa; expected %d", + "DKIM key is has invalid length %d for eddsa; expected %zd", (int) key->decoded_len, - rspamd_cryptobox_pk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519)); + crypto_sign_publickeybytes()); REF_RELEASE(key); return NULL; } } else { - key->key_bio = BIO_new_mem_buf(key->keydata, key->decoded_len); + key->specific.key_ssl.key_bio = BIO_new_mem_buf(key->keydata, key->decoded_len); - if (key->key_bio == NULL) { + if (key->specific.key_ssl.key_bio == NULL) { g_set_error(err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL, @@ -1419,9 +1418,9 @@ rspamd_dkim_make_key(const char *keydata, return NULL; } - key->key_evp = d2i_PUBKEY_bio(key->key_bio, NULL); + key->specific.key_ssl.key_evp = d2i_PUBKEY_bio(key->specific.key_ssl.key_bio, NULL); - if (key->key_evp == NULL) { + if (key->specific.key_ssl.key_evp == NULL) { g_set_error(err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL, @@ -1430,33 +1429,6 @@ rspamd_dkim_make_key(const char *keydata, return NULL; } - - if (type == RSPAMD_DKIM_KEY_RSA) { - key->key.key_rsa = EVP_PKEY_get1_RSA(key->key_evp); - - if (key->key.key_rsa == NULL) { - g_set_error(err, - DKIM_ERROR, - DKIM_SIGERROR_KEYFAIL, - "cannot extract rsa key from evp key"); - REF_RELEASE(key); - - return NULL; - } - } - else { - key->key.key_ecdsa = EVP_PKEY_get1_EC_KEY(key->key_evp); - - if (key->key.key_ecdsa == NULL) { - g_set_error(err, - DKIM_ERROR, - DKIM_SIGERROR_KEYFAIL, - "cannot extract ecdsa key from evp key"); - REF_RELEASE(key); - - return NULL; - } - } } return key; @@ -1473,29 +1445,19 @@ rspamd_dkim_key_id(rspamd_dkim_key_t *key) } /** - * Free DKIM key - * @param key - */ +* Free DKIM key +* @param key +*/ void rspamd_dkim_key_free(rspamd_dkim_key_t *key) { - if (key->key_evp) { - EVP_PKEY_free(key->key_evp); - } - - if (key->type == RSPAMD_DKIM_KEY_RSA) { - if (key->key.key_rsa) { - RSA_free(key->key.key_rsa); + if (key->type != RSPAMD_DKIM_KEY_EDDSA) { + if (key->specific.key_ssl.key_evp) { + EVP_PKEY_free(key->specific.key_ssl.key_evp); } - } - else if (key->type == RSPAMD_DKIM_KEY_ECDSA) { - if (key->key.key_ecdsa) { - EC_KEY_free(key->key.key_ecdsa); + if (key->specific.key_ssl.key_bio) { + BIO_free(key->specific.key_ssl.key_bio); } } - /* Nothing in case of eddsa key */ - if (key->key_bio) { - BIO_free(key->key_bio); - } g_free(key->raw_key); g_free(key->keydata); @@ -1504,20 +1466,16 @@ void rspamd_dkim_key_free(rspamd_dkim_key_t *key) void rspamd_dkim_sign_key_free(rspamd_dkim_sign_key_t *key) { - if (key->key_evp) { - EVP_PKEY_free(key->key_evp); - } - if (key->type == RSPAMD_DKIM_KEY_RSA) { - if (key->key.key_rsa) { - RSA_free(key->key.key_rsa); + if (key->type != RSPAMD_DKIM_KEY_EDDSA) { + if (key->specific.key_ssl.key_evp) { + EVP_PKEY_free(key->specific.key_ssl.key_evp); + } + if (key->specific.key_ssl.key_bio) { + BIO_free(key->specific.key_ssl.key_bio); } } - if (key->key_bio) { - BIO_free(key->key_bio); - } - - if (key->type == RSPAMD_DKIM_KEY_EDDSA) { - rspamd_explicit_memzero(key->key.key_eddsa, key->keylen); + else { + rspamd_explicit_memzero(key->specific.key_eddsa, key->keylen); g_free(key->keydata); } @@ -1570,9 +1528,9 @@ rspamd_dkim_parse_key(const char *txt, gsize *keylen, GError **err) break; case read_tag_before_eqsign: /* Input: spaces before eqsign - * Output: either read a next tag (previous had no value), or read value - * p is moved forward - */ + * Output: either read a next tag (previous had no value), or read value + * p is moved forward + */ if (*p == '=') { state = read_eqsign; } @@ -1759,12 +1717,12 @@ rspamd_dkim_dns_cb(struct rdns_reply *reply, gpointer arg) } /** - * Make DNS request for specified context and obtain and parse key - * @param ctx dkim context from signature - * @param resolver dns resolver object - * @param s async session to make request - * @return - */ +* Make DNS request for specified context and obtain and parse key +* @param ctx dkim context from signature +* @param resolver dns resolver object +* @param s async session to make request +* @return +*/ gboolean rspamd_get_dkim_key(rspamd_dkim_context_t *ctx, struct rspamd_task *task, @@ -2187,8 +2145,8 @@ rspamd_dkim_canonize_body(struct rspamd_task *task, ; /* - * If we have l= tag then we cannot add crlf... - */ + * If we have l= tag then we cannot add crlf... + */ if (need_crlf) { /* l is evil... */ if (ctx->len == 0) { @@ -2241,7 +2199,6 @@ rspamd_dkim_canonize_body(struct rspamd_task *task, return TRUE; } - /* TODO: Implement relaxed algorithm */ return FALSE; } @@ -2461,9 +2418,9 @@ rspamd_dkim_canonize_header(struct rspamd_dkim_common_ctx *ctx, bool use_idx = false, is_sign = ctx->is_sign; /* - * TODO: - * Temporary hack to prevent linked list being misused until refactored - */ + * TODO: + * Temporary hack to prevent linked list being misused until refactored + */ const unsigned int max_list_iters = 1000; if (count < 0) { @@ -2509,17 +2466,17 @@ rspamd_dkim_canonize_header(struct rspamd_dkim_common_ctx *ctx, if (hdr_cnt <= count) { /* - * If DKIM has less headers requested than there are in a - * message, then it's fine, it allows adding extra headers - */ + * If DKIM has less headers requested than there are in a + * message, then it's fine, it allows adding extra headers + */ return TRUE; } } else { /* - * This branch is used for ARC headers, and it orders them based on - * i=<number> string and not their real order in the list of headers - */ + * This branch is used for ARC headers, and it orders them based on + * i=<number> string and not their real order in the list of headers + */ char idx_buf[16]; int id_len, i; @@ -2692,12 +2649,12 @@ rspamd_dkim_type_to_string(enum rspamd_dkim_type t) } /** - * Check task for dkim context using dkim key - * @param ctx dkim verify context - * @param key dkim key (from cache or from dns request) - * @param task task to check - * @return - */ +* Check task for dkim context using dkim key +* @param ctx dkim verify context +* @param key dkim key (from cache or from dns request) +* @param task task to check +* @return +*/ struct rspamd_dkim_check_result * rspamd_dkim_check(rspamd_dkim_context_t *ctx, rspamd_dkim_key_t *key, @@ -2913,11 +2870,10 @@ rspamd_dkim_check(rspamd_dkim_context_t *ctx, /* Not reached */ nid = NID_sha1; } - switch (key->type) { case RSPAMD_DKIM_KEY_RSA: - if (RSA_verify(nid, raw_digest, dlen, ctx->b, ctx->blen, - key->key.key_rsa) != 1) { + if (!rspamd_cryptobox_verify_evp_rsa(nid, ctx->b, ctx->blen, raw_digest, dlen, + key->specific.key_ssl.key_evp)) { msg_debug_dkim("headers rsa verify failed"); ERR_clear_error(); res->rcode = DKIM_REJECT; @@ -2935,8 +2891,8 @@ rspamd_dkim_check(rspamd_dkim_context_t *ctx, } break; case RSPAMD_DKIM_KEY_ECDSA: - if (ECDSA_verify(nid, raw_digest, dlen, ctx->b, ctx->blen, - key->key.key_ecdsa) != 1) { + if (rspamd_cryptobox_verify_evp_ecdsa(nid, ctx->b, ctx->blen, raw_digest, dlen, + key->specific.key_ssl.key_evp) != 1) { msg_info_dkim( "%s: headers ECDSA verification failure; " "body length %d->%d; headers length %d; d=%s; s=%s; key_md5=%*xs; orig header: %s", @@ -2952,9 +2908,10 @@ rspamd_dkim_check(rspamd_dkim_context_t *ctx, res->fail_reason = "headers ecdsa verify failed"; } break; + case RSPAMD_DKIM_KEY_EDDSA: if (!rspamd_cryptobox_verify(ctx->b, ctx->blen, raw_digest, dlen, - key->key.key_eddsa, RSPAMD_CRYPTOBOX_MODE_25519)) { + key->specific.key_eddsa)) { msg_info_dkim( "%s: headers EDDSA verification failure; " "body length %d->%d; headers length %d; d=%s; s=%s; key_md5=%*xs; orig header: %s", @@ -3155,30 +3112,29 @@ rspamd_dkim_sign_key_load(const char *key, gsize len, } if (type == RSPAMD_DKIM_KEY_RAW && (len == 32 || - len == rspamd_cryptobox_sk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519))) { + len == crypto_sign_secretkeybytes())) { if (len == 32) { /* Seeded key, need scalarmult */ unsigned char pk[32]; nkey->type = RSPAMD_DKIM_KEY_EDDSA; - nkey->key.key_eddsa = g_malloc( - rspamd_cryptobox_sk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519)); - crypto_sign_ed25519_seed_keypair(pk, nkey->key.key_eddsa, key); - nkey->keylen = rspamd_cryptobox_sk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519); + nkey->specific.key_eddsa = g_malloc(crypto_sign_secretkeybytes()); + crypto_sign_ed25519_seed_keypair(pk, nkey->specific.key_eddsa, key); + nkey->keylen = crypto_sign_secretkeybytes(); } else { /* Full ed25519 key */ - unsigned klen = rspamd_cryptobox_sk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519); + unsigned klen = crypto_sign_secretkeybytes(); nkey->type = RSPAMD_DKIM_KEY_EDDSA; - nkey->key.key_eddsa = g_malloc(klen); - memcpy(nkey->key.key_eddsa, key, klen); + nkey->specific.key_eddsa = g_malloc(klen); + memcpy(nkey->specific.key_eddsa, key, klen); nkey->keylen = klen; } } else { - nkey->key_bio = BIO_new_mem_buf(key, len); + nkey->specific.key_ssl.key_bio = BIO_new_mem_buf(key, len); if (type == RSPAMD_DKIM_KEY_RAW) { - if (d2i_PrivateKey_bio(nkey->key_bio, &nkey->key_evp) == NULL) { + if (d2i_PrivateKey_bio(nkey->specific.key_ssl.key_bio, &nkey->specific.key_ssl.key_evp) == NULL) { g_set_error(err, dkim_error_quark(), DKIM_SIGERROR_KEYFAIL, "cannot parse raw private key: %s", ERR_error_string(ERR_get_error(), NULL)); @@ -3190,7 +3146,7 @@ rspamd_dkim_sign_key_load(const char *key, gsize len, } } else { - if (!PEM_read_bio_PrivateKey(nkey->key_bio, &nkey->key_evp, NULL, NULL)) { + if (!PEM_read_bio_PrivateKey(nkey->specific.key_ssl.key_bio, &nkey->specific.key_ssl.key_evp, NULL, NULL)) { g_set_error(err, dkim_error_quark(), DKIM_SIGERROR_KEYFAIL, "cannot parse pem private key: %s", ERR_error_string(ERR_get_error(), NULL)); @@ -3200,18 +3156,6 @@ rspamd_dkim_sign_key_load(const char *key, gsize len, goto end; } } - nkey->key.key_rsa = EVP_PKEY_get1_RSA(nkey->key_evp); - if (nkey->key.key_rsa == NULL) { - g_set_error(err, - DKIM_ERROR, - DKIM_SIGERROR_KEYFAIL, - "cannot extract rsa key from evp key"); - rspamd_dkim_sign_key_free(nkey); - nkey = NULL; - - goto end; - } - nkey->type = RSPAMD_DKIM_KEY_RSA; } REF_INIT_RETAIN(nkey, rspamd_dkim_sign_key_free); @@ -3269,7 +3213,7 @@ rspamd_create_dkim_sign_context(struct rspamd_task *task, return NULL; } - if (!priv_key || (!priv_key->key.key_rsa && !priv_key->key.key_eddsa)) { + if (!priv_key) { g_set_error(err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL, @@ -3536,12 +3480,34 @@ rspamd_dkim_sign(struct rspamd_task *task, const char *selector, dlen = EVP_MD_CTX_size(ctx->common.headers_hash); EVP_DigestFinal_ex(ctx->common.headers_hash, raw_digest, NULL); + if (ctx->key->type == RSPAMD_DKIM_KEY_RSA) { - sig_len = RSA_size(ctx->key->key.key_rsa); + sig_len = EVP_PKEY_size(ctx->key->specific.key_ssl.key_evp); sig_buf = g_alloca(sig_len); + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ctx->key->specific.key_ssl.key_evp, NULL); + if (EVP_PKEY_sign_init(pctx) <= 0) { + g_string_free(hdr, TRUE); + msg_err_task("rsa sign error: %s", + ERR_error_string(ERR_get_error(), NULL)); + + return NULL; + } + if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) <= 0) { + g_string_free(hdr, TRUE); + msg_err_task("rsa sign error: %s", + ERR_error_string(ERR_get_error(), NULL)); - if (RSA_sign(NID_sha256, raw_digest, dlen, sig_buf, &sig_len, - ctx->key->key.key_rsa) != 1) { + return NULL; + } + if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha256()) <= 0) { + g_string_free(hdr, TRUE); + msg_err_task("rsa sign error: %s", + ERR_error_string(ERR_get_error(), NULL)); + + return NULL; + } + size_t sig_len_size_t = sig_len; + if (EVP_PKEY_sign(pctx, sig_buf, &sig_len_size_t, raw_digest, dlen) <= 0) { g_string_free(hdr, TRUE); msg_err_task("rsa sign error: %s", ERR_error_string(ERR_get_error(), NULL)); @@ -3550,11 +3516,10 @@ rspamd_dkim_sign(struct rspamd_task *task, const char *selector, } } else if (ctx->key->type == RSPAMD_DKIM_KEY_EDDSA) { - sig_len = rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519); + sig_len = crypto_sign_bytes(); sig_buf = g_alloca(sig_len); - rspamd_cryptobox_sign(sig_buf, NULL, raw_digest, dlen, - ctx->key->key.key_eddsa, RSPAMD_CRYPTOBOX_MODE_25519); + rspamd_cryptobox_sign(sig_buf, NULL, raw_digest, dlen, ctx->key->specific.key_eddsa); } else { g_string_free(hdr, TRUE); @@ -3595,17 +3560,25 @@ rspamd_dkim_match_keys(rspamd_dkim_key_t *pk, } if (pk->type == RSPAMD_DKIM_KEY_EDDSA) { - if (memcmp(sk->key.key_eddsa + 32, pk->key.key_eddsa, 32) != 0) { + if (memcmp(sk->specific.key_eddsa + 32, pk->specific.key_eddsa, 32) != 0) { g_set_error(err, dkim_error_quark(), DKIM_SIGERROR_KEYHASHMISMATCH, "pubkey does not match private key"); return FALSE; } } - else if (EVP_PKEY_cmp(pk->key_evp, sk->key_evp) != 1) { +#if OPENSSL_VERSION_MAJOR >= 3 + else if (EVP_PKEY_eq(pk->specific.key_ssl.key_evp, sk->specific.key_ssl.key_evp) != 1) { g_set_error(err, dkim_error_quark(), DKIM_SIGERROR_KEYHASHMISMATCH, "pubkey does not match private key"); return FALSE; } +#else + else if (EVP_PKEY_cmp(pk->specific.key_ssl.key_evp, sk->specific.key_ssl.key_evp) != 1) { + g_set_error(err, dkim_error_quark(), DKIM_SIGERROR_KEYHASHMISMATCH, + "pubkey does not match private key"); + return FALSE; + } +#endif return TRUE; } diff --git a/src/libserver/http/http_connection.c b/src/libserver/http/http_connection.c index ef39e11e7..1ae9bb034 100644 --- a/src/libserver/http/http_connection.c +++ b/src/libserver/http/http_connection.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -159,8 +159,7 @@ rspamd_http_parse_key(rspamd_ftok_t *data, struct rspamd_http_connection *conn, if (decoded_id != NULL && id_len >= RSPAMD_KEYPAIR_SHORT_ID_LEN) { pk = rspamd_pubkey_from_base32(eq_pos + 1, data->begin + data->len - eq_pos - 1, - RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + RSPAMD_KEYPAIR_KEX); if (pk != NULL) { if (memcmp(rspamd_keypair_get_id(priv->local_key), decoded_id, @@ -572,21 +571,18 @@ rspamd_http_decrypt_message(struct rspamd_http_connection *conn, struct rspamd_http_header *hdr, *hcur, *hcurtmp; struct http_parser decrypted_parser; struct http_parser_settings decrypted_cb; - enum rspamd_cryptobox_mode mode; - mode = rspamd_keypair_alg(priv->local_key); nonce = msg->body_buf.str; - m = msg->body_buf.str + rspamd_cryptobox_nonce_bytes(mode) + - rspamd_cryptobox_mac_bytes(mode); - dec_len = msg->body_buf.len - rspamd_cryptobox_nonce_bytes(mode) - - rspamd_cryptobox_mac_bytes(mode); + m = msg->body_buf.str + crypto_box_noncebytes() + + crypto_box_macbytes(); + dec_len = msg->body_buf.len - crypto_box_noncebytes() - crypto_box_macbytes(); if ((nm = rspamd_pubkey_get_nm(peer_key, priv->local_key)) == NULL) { nm = rspamd_pubkey_calculate_nm(peer_key, priv->local_key); } if (!rspamd_cryptobox_decrypt_nm_inplace(m, dec_len, nonce, - nm, m - rspamd_cryptobox_mac_bytes(mode), mode)) { + nm, m - crypto_box_macbytes())) { msg_err("cannot verify encrypted message, first bytes of the input: %*xs", (int) MIN(msg->body_buf.len, 64), msg->body_buf.begin); return -1; @@ -640,7 +636,6 @@ rspamd_http_on_message_complete(http_parser *parser) (struct rspamd_http_connection *) parser->data; struct rspamd_http_connection_private *priv; int ret = 0; - enum rspamd_cryptobox_mode mode; if (conn->finished) { return 0; @@ -655,11 +650,10 @@ rspamd_http_on_message_complete(http_parser *parser) } if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) == 0 && IS_CONN_ENCRYPTED(priv)) { - mode = rspamd_keypair_alg(priv->local_key); if (priv->local_key == NULL || priv->msg->peer_key == NULL || - priv->msg->body_buf.len < rspamd_cryptobox_nonce_bytes(mode) + - rspamd_cryptobox_mac_bytes(mode)) { + priv->msg->body_buf.len < crypto_box_noncebytes() + + crypto_box_macbytes()) { msg_err("cannot decrypt message"); return -1; } @@ -1576,10 +1570,8 @@ rspamd_http_connection_encrypt_message( int i, cnt; unsigned int outlen; struct rspamd_http_header *hdr, *hcur; - enum rspamd_cryptobox_mode mode; - mode = rspamd_keypair_alg(priv->local_key); - crlfp = mp + rspamd_cryptobox_mac_bytes(mode); + crlfp = mp + crypto_box_macbytes(); outlen = priv->out[0].iov_len + priv->out[1].iov_len; /* @@ -1632,7 +1624,7 @@ if ((nm = rspamd_pubkey_get_nm(peer_key, priv->local_key)) == NULL) { nm = rspamd_pubkey_calculate_nm(peer_key, priv->local_key); } -rspamd_cryptobox_encryptv_nm_inplace(segments, cnt, np, nm, mp, mode); +rspamd_cryptobox_encryptv_nm_inplace(segments, cnt, np, nm, mp); /* * iov[0] = base HTTP request @@ -1642,12 +1634,12 @@ rspamd_cryptobox_encryptv_nm_inplace(segments, cnt, np, nm, mp, mode); * iov[4..i] = encrypted HTTP request/reply */ priv->out[2].iov_base = np; -priv->out[2].iov_len = rspamd_cryptobox_nonce_bytes(mode); +priv->out[2].iov_len = crypto_box_noncebytes(); priv->out[3].iov_base = mp; -priv->out[3].iov_len = rspamd_cryptobox_mac_bytes(mode); +priv->out[3].iov_len = crypto_box_macbytes(); -outlen += rspamd_cryptobox_nonce_bytes(mode) + - rspamd_cryptobox_mac_bytes(mode); +outlen += crypto_box_noncebytes() + + crypto_box_macbytes(); for (i = 0; i < cnt; i++) { priv->out[i + 4].iov_base = segments[i].data; @@ -2027,7 +2019,6 @@ rspamd_http_connection_write_message_common(struct rspamd_http_connection *conn, unsigned char nonce[rspamd_cryptobox_MAX_NONCEBYTES], mac[rspamd_cryptobox_MAX_MACBYTES]; unsigned char *np = NULL, *mp = NULL, *meth_pos = NULL; struct rspamd_cryptobox_pubkey *peer_key = NULL; - enum rspamd_cryptobox_mode mode; GError *err; conn->ud = ud; @@ -2059,8 +2050,7 @@ rspamd_http_connection_write_message_common(struct rspamd_http_connection *conn, if (msg->peer_key != NULL) { if (priv->local_key == NULL) { /* Automatically generate a temporary keypair */ - priv->local_key = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + priv->local_key = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX); } encrypted = TRUE; @@ -2128,8 +2118,6 @@ rspamd_http_connection_write_message_common(struct rspamd_http_connection *conn, } if (encrypted) { - mode = rspamd_keypair_alg(priv->local_key); - if (msg->body_buf.len == 0) { pbody = NULL; bodylen = 0; @@ -2154,8 +2142,8 @@ rspamd_http_connection_write_message_common(struct rspamd_http_connection *conn, * [iov[n + 2] = encrypted body] */ priv->outlen = 7; - enclen = rspamd_cryptobox_nonce_bytes(mode) + - rspamd_cryptobox_mac_bytes(mode) + + enclen = crypto_box_noncebytes() + + crypto_box_macbytes() + 4 + /* 2 * CRLF */ bodylen; } @@ -2197,8 +2185,8 @@ rspamd_http_connection_write_message_common(struct rspamd_http_connection *conn, ENCRYPTED_VERSION); } - enclen = rspamd_cryptobox_nonce_bytes(mode) + - rspamd_cryptobox_mac_bytes(mode) + + enclen = crypto_box_noncebytes() + + crypto_box_macbytes() + preludelen + /* version [content-length] + 2 * CRLF */ bodylen; } @@ -2275,10 +2263,9 @@ priv->out[0].iov_len = buf->len; /* Buf will be used eventually for encryption */ if (encrypted) { int meth_offset, nonce_offset, mac_offset; - mode = rspamd_keypair_alg(priv->local_key); - ottery_rand_bytes(nonce, rspamd_cryptobox_nonce_bytes(mode)); - memset(mac, 0, rspamd_cryptobox_mac_bytes(mode)); + ottery_rand_bytes(nonce, crypto_box_noncebytes()); + memset(mac, 0, crypto_box_macbytes()); meth_offset = buf->len; if (conn->type == RSPAMD_HTTP_SERVER) { @@ -2292,11 +2279,9 @@ if (encrypted) { } nonce_offset = buf->len; - buf = rspamd_fstring_append(buf, nonce, - rspamd_cryptobox_nonce_bytes(mode)); + buf = rspamd_fstring_append(buf, nonce, crypto_box_noncebytes()); mac_offset = buf->len; - buf = rspamd_fstring_append(buf, mac, - rspamd_cryptobox_mac_bytes(mode)); + buf = rspamd_fstring_append(buf, mac, crypto_box_macbytes()); /* Need to be encrypted */ if (conn->type == RSPAMD_HTTP_SERVER) { @@ -2365,44 +2350,44 @@ if (conn->opts & RSPAMD_HTTP_CLIENT_SSL) { gpointer ssl_ctx = (msg->flags & RSPAMD_HTTP_FLAG_SSL_NOVERIFY) ? priv->ctx->ssl_ctx_noverify : priv->ctx->ssl_ctx; if (!ssl_ctx) { - err = g_error_new(HTTP_ERROR, 400, "ssl message requested " - "with no ssl ctx"); - rspamd_http_connection_ref(conn); - conn->error_handler(conn, err); - rspamd_http_connection_unref(conn); - g_error_free(err); - return FALSE; + err = g_error_new(HTTP_ERROR, 400, "ssl message requested " + "with no ssl ctx"); + rspamd_http_connection_ref(conn); + conn->error_handler(conn, err); + rspamd_http_connection_unref(conn); + g_error_free(err); + return FALSE; } else { - if (!priv->ssl) { - priv->ssl = rspamd_ssl_connection_new(ssl_ctx, priv->ctx->event_loop, - !(msg->flags & RSPAMD_HTTP_FLAG_SSL_NOVERIFY), - conn->log_tag); - g_assert(priv->ssl != NULL); - - if (!rspamd_ssl_connect_fd(priv->ssl, conn->fd, host, &priv->ev, - priv->timeout, rspamd_http_event_handler, - rspamd_http_ssl_err_handler, conn)) { - - err = g_error_new(HTTP_ERROR, 400, - "ssl connection error: ssl error=%s, errno=%s", - ERR_error_string(ERR_get_error(), NULL), - strerror(errno)); - rspamd_http_connection_ref(conn); - conn->error_handler(conn, err); - rspamd_http_connection_unref(conn); - g_error_free(err); - return FALSE; - } - } - else { - /* Just restore SSL handlers */ - rspamd_ssl_connection_restore_handlers(priv->ssl, - rspamd_http_event_handler, - rspamd_http_ssl_err_handler, - conn, - EV_WRITE); + if (!priv->ssl) { + priv->ssl = rspamd_ssl_connection_new(ssl_ctx, priv->ctx->event_loop, + !(msg->flags & RSPAMD_HTTP_FLAG_SSL_NOVERIFY), + conn->log_tag); + g_assert(priv->ssl != NULL); + + if (!rspamd_ssl_connect_fd(priv->ssl, conn->fd, host, &priv->ev, + priv->timeout, rspamd_http_event_handler, + rspamd_http_ssl_err_handler, conn)) { + + err = g_error_new(HTTP_ERROR, 400, + "ssl connection error: ssl error=%s, errno=%s", + ERR_error_string(ERR_get_error(), NULL), + strerror(errno)); + rspamd_http_connection_ref(conn); + conn->error_handler(conn, err); + rspamd_http_connection_unref(conn); + g_error_free(err); + return FALSE; } + } + else { + /* Just restore SSL handlers */ + rspamd_ssl_connection_restore_handlers(priv->ssl, + rspamd_http_event_handler, + rspamd_http_ssl_err_handler, + conn, + EV_WRITE); + } } } else { @@ -2467,10 +2452,10 @@ rspamd_http_connection_get_peer_key(struct rspamd_http_connection *conn) struct rspamd_http_connection_private *priv = conn->priv; if (priv->peer_key) { - return priv->peer_key; + return priv->peer_key; } else if (priv->msg) { - return priv->msg->peer_key; + return priv->msg->peer_key; } return NULL; @@ -2482,10 +2467,10 @@ rspamd_http_connection_is_encrypted(struct rspamd_http_connection *conn) struct rspamd_http_connection_private *priv = conn->priv; if (priv->peer_key != NULL) { - return TRUE; + return TRUE; } else if (priv->msg) { - return priv->msg->peer_key != NULL; + return priv->msg->peer_key != NULL; } return FALSE; @@ -2512,103 +2497,103 @@ rspamd_http_message_parse_query(struct rspamd_http_message *msg) rspamd_fstring_mapped_ftok_free); if (msg->url && msg->url->len > 0) { - http_parser_parse_url(msg->url->str, msg->url->len, TRUE, &u); - - if (u.field_set & (1 << UF_QUERY)) { - p = msg->url->str + u.field_data[UF_QUERY].off; - c = p; - end = p + u.field_data[UF_QUERY].len; - - while (p <= end) { - switch (state) { - case parse_key: - if ((p == end || *p == '&') && p > c) { - /* We have a single parameter without a value */ - key = rspamd_fstring_new_init(c, p - c); - key_tok = rspamd_ftok_map(key); - key_tok->len = rspamd_url_decode(key->str, key->str, - key->len); - - value = rspamd_fstring_new_init("", 0); - value_tok = rspamd_ftok_map(value); + http_parser_parse_url(msg->url->str, msg->url->len, TRUE, &u); + + if (u.field_set & (1 << UF_QUERY)) { + p = msg->url->str + u.field_data[UF_QUERY].off; + c = p; + end = p + u.field_data[UF_QUERY].len; + + while (p <= end) { + switch (state) { + case parse_key: + if ((p == end || *p == '&') && p > c) { + /* We have a single parameter without a value */ + key = rspamd_fstring_new_init(c, p - c); + key_tok = rspamd_ftok_map(key); + key_tok->len = rspamd_url_decode(key->str, key->str, + key->len); + + value = rspamd_fstring_new_init("", 0); + value_tok = rspamd_ftok_map(value); + + g_hash_table_replace(res, key_tok, value_tok); + state = parse_ampersand; + } + else if (*p == '=' && p > c) { + /* We have something like key=value */ + key = rspamd_fstring_new_init(c, p - c); + key_tok = rspamd_ftok_map(key); + key_tok->len = rspamd_url_decode(key->str, key->str, + key->len); + + state = parse_eqsign; + } + else { + p++; + } + break; - g_hash_table_replace(res, key_tok, value_tok); - state = parse_ampersand; - } - else if (*p == '=' && p > c) { - /* We have something like key=value */ - key = rspamd_fstring_new_init(c, p - c); - key_tok = rspamd_ftok_map(key); - key_tok->len = rspamd_url_decode(key->str, key->str, - key->len); - - state = parse_eqsign; - } - else { - p++; - } - break; + case parse_eqsign: + if (*p != '=') { + c = p; + state = parse_value; + } + else { + p++; + } + break; - case parse_eqsign: - if (*p != '=') { - c = p; - state = parse_value; - } - else { - p++; - } - break; - - case parse_value: - if ((p == end || *p == '&') && p >= c) { - g_assert(key != NULL); - if (p > c) { - value = rspamd_fstring_new_init(c, p - c); - value_tok = rspamd_ftok_map(value); - value_tok->len = rspamd_url_decode(value->str, - value->str, - value->len); - /* Detect quotes for value */ - if (value_tok->begin[0] == '"') { - memmove(value->str, value->str + 1, - value_tok->len - 1); - value_tok->len--; - } - if (value_tok->begin[value_tok->len - 1] == '"') { - value_tok->len--; - } + case parse_value: + if ((p == end || *p == '&') && p >= c) { + g_assert(key != NULL); + if (p > c) { + value = rspamd_fstring_new_init(c, p - c); + value_tok = rspamd_ftok_map(value); + value_tok->len = rspamd_url_decode(value->str, + value->str, + value->len); + /* Detect quotes for value */ + if (value_tok->begin[0] == '"') { + memmove(value->str, value->str + 1, + value_tok->len - 1); + value_tok->len--; } - else { - value = rspamd_fstring_new_init("", 0); - value_tok = rspamd_ftok_map(value); + if (value_tok->begin[value_tok->len - 1] == '"') { + value_tok->len--; } - - g_hash_table_replace(res, key_tok, value_tok); - key = value = NULL; - key_tok = value_tok = NULL; - state = parse_ampersand; } else { - p++; + value = rspamd_fstring_new_init("", 0); + value_tok = rspamd_ftok_map(value); } - break; - case parse_ampersand: - if (p != end && *p != '&') { - c = p; - state = parse_key; - } - else { - p++; - } - break; + g_hash_table_replace(res, key_tok, value_tok); + key = value = NULL; + key_tok = value_tok = NULL; + state = parse_ampersand; + } + else { + p++; + } + break; + + case parse_ampersand: + if (p != end && *p != '&') { + c = p; + state = parse_key; + } + else { + p++; } + break; } } + } - if (state != parse_ampersand && key != NULL) { - rspamd_fstring_free(key); - } + if (state != parse_ampersand && key != NULL) { + rspamd_fstring_free(key); + } } return res; @@ -2635,15 +2620,15 @@ void rspamd_http_connection_disable_encryption(struct rspamd_http_connection *co priv = conn->priv; if (priv) { - if (priv->local_key) { - rspamd_keypair_unref(priv->local_key); - } - if (priv->peer_key) { - rspamd_pubkey_unref(priv->peer_key); - } + if (priv->local_key) { + rspamd_keypair_unref(priv->local_key); + } + if (priv->peer_key) { + rspamd_pubkey_unref(priv->peer_key); + } - priv->local_key = NULL; - priv->peer_key = NULL; - priv->flags &= ~RSPAMD_HTTP_CONN_FLAG_ENCRYPTED; + priv->local_key = NULL; + priv->peer_key = NULL; + priv->flags &= ~RSPAMD_HTTP_CONN_FLAG_ENCRYPTED; } }
\ No newline at end of file diff --git a/src/libserver/http/http_context.c b/src/libserver/http/http_context.c index fe9412fe2..df32a2258 100644 --- a/src/libserver/http/http_context.c +++ b/src/libserver/http/http_context.c @@ -77,8 +77,7 @@ rspamd_http_context_client_rotate_ev(struct ev_loop *loop, ev_timer *w, int reve ev_timer_again(loop, w); kp = ctx->client_kp; - ctx->client_kp = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + ctx->client_kp = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX); rspamd_keypair_unref(kp); } diff --git a/src/libserver/logger/logger.c b/src/libserver/logger/logger.c index 13bac5cbe..25818e7a5 100644 --- a/src/libserver/logger/logger.c +++ b/src/libserver/logger/logger.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 Vsevolod Stakhov + * Copyright 2024 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -277,8 +277,7 @@ rspamd_log_open_specific(rspamd_mempool_t *pool, if (cfg->log_encryption_key) { logger->pk = rspamd_pubkey_ref(cfg->log_encryption_key); - logger->keypair = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + logger->keypair = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX); rspamd_pubkey_calculate_nm(logger->pk, logger->keypair); } } @@ -342,9 +341,9 @@ rspamd_log_encrypt_message(const char *begin, const char *end, gsize *enc_len, g_assert(end > begin); /* base64 (pubkey | nonce | message) */ - inlen = rspamd_cryptobox_nonce_bytes(RSPAMD_CRYPTOBOX_MODE_25519) + - rspamd_cryptobox_pk_bytes(RSPAMD_CRYPTOBOX_MODE_25519) + - rspamd_cryptobox_mac_bytes(RSPAMD_CRYPTOBOX_MODE_25519) + + inlen = crypto_box_noncebytes() + + crypto_box_publickeybytes() + + crypto_box_macbytes() + (end - begin); out = g_malloc(inlen); @@ -352,16 +351,15 @@ rspamd_log_encrypt_message(const char *begin, const char *end, gsize *enc_len, comp = rspamd_pubkey_get_pk(rspamd_log->pk, &len); memcpy(p, comp, len); p += len; - ottery_rand_bytes(p, rspamd_cryptobox_nonce_bytes(RSPAMD_CRYPTOBOX_MODE_25519)); + ottery_rand_bytes(p, crypto_box_noncebytes()); nonce = p; - p += rspamd_cryptobox_nonce_bytes(RSPAMD_CRYPTOBOX_MODE_25519); + p += crypto_box_noncebytes(); mac = p; - p += rspamd_cryptobox_mac_bytes(RSPAMD_CRYPTOBOX_MODE_25519); + p += crypto_box_macbytes(); memcpy(p, begin, end - begin); comp = rspamd_pubkey_get_nm(rspamd_log->pk, rspamd_log->keypair); g_assert(comp != NULL); - rspamd_cryptobox_encrypt_nm_inplace(p, end - begin, nonce, comp, mac, - RSPAMD_CRYPTOBOX_MODE_25519); + rspamd_cryptobox_encrypt_nm_inplace(p, end - begin, nonce, comp, mac); b64 = rspamd_encode_base64(out, inlen, 0, enc_len); g_free(out); diff --git a/src/libserver/maps/map.c b/src/libserver/maps/map.c index 15fce7e9d..631455755 100644 --- a/src/libserver/maps/map.c +++ b/src/libserver/maps/map.c @@ -670,14 +670,14 @@ rspamd_map_check_sig_pk_mem(const unsigned char *sig, GString *b32_key; gboolean ret = TRUE; - if (siglen != rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519)) { + if (siglen != crypto_sign_bytes()) { msg_err_map("can't open signature for %s: invalid size: %z", map->name, siglen); ret = FALSE; } if (ret && !rspamd_cryptobox_verify(sig, siglen, input, inlen, - rspamd_pubkey_get_pk(pk, NULL), RSPAMD_CRYPTOBOX_MODE_25519)) { + rspamd_pubkey_get_pk(pk, NULL))) { msg_err_map("can't verify signature for %s: incorrect signature", map->name); ret = FALSE; @@ -718,8 +718,7 @@ rspamd_map_check_file_sig(const char *fname, return FALSE; } - pk = rspamd_pubkey_from_base32(data, len, RSPAMD_KEYPAIR_SIGN, - RSPAMD_CRYPTOBOX_MODE_25519); + pk = rspamd_pubkey_from_base32(data, len, RSPAMD_KEYPAIR_SIGN); munmap(data, len); if (pk == NULL) { @@ -2414,8 +2413,7 @@ rspamd_map_check_proto(struct rspamd_config *cfg, end_key = memchr(pos, '+', end - pos); if (end_key != NULL) { - bk->trusted_pubkey = rspamd_pubkey_from_base32(pos, end_key - pos, - RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519); + bk->trusted_pubkey = rspamd_pubkey_from_base32(pos, end_key - pos, RSPAMD_KEYPAIR_SIGN); if (bk->trusted_pubkey == NULL) { msg_err_config("cannot read pubkey from map: %s", @@ -2426,8 +2424,7 @@ rspamd_map_check_proto(struct rspamd_config *cfg, } else if (end - pos > 64) { /* Try hex encoding */ - bk->trusted_pubkey = rspamd_pubkey_from_hex(pos, 64, - RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519); + bk->trusted_pubkey = rspamd_pubkey_from_hex(pos, 64, RSPAMD_KEYPAIR_SIGN); if (bk->trusted_pubkey == NULL) { msg_err_config("cannot read pubkey from map: %s", diff --git a/src/libserver/milter.c b/src/libserver/milter.c index f35278a0e..94b0d6cc1 100644 --- a/src/libserver/milter.c +++ b/src/libserver/milter.c @@ -1465,10 +1465,16 @@ rspamd_milter_macro_http(struct rspamd_milter_session *session, return; } + /* + * When we get a queue-id we try to pass it to the backend, where possible + * We also need that for logging consistency + */ IF_MACRO("{i}") { rspamd_http_message_add_header_len(msg, QUEUE_ID_HEADER, found->begin, found->len); + rspamd_http_message_add_header_len(msg, LOG_TAG_HEADER, + found->begin, found->len); } else { @@ -1476,6 +1482,8 @@ rspamd_milter_macro_http(struct rspamd_milter_session *session, { rspamd_http_message_add_header_len(msg, QUEUE_ID_HEADER, found->begin, found->len); + rspamd_http_message_add_header_len(msg, LOG_TAG_HEADER, + found->begin, found->len); } } diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c index db83b0bfb..ee2192913 100644 --- a/src/libserver/protocol.c +++ b/src/libserver/protocol.c @@ -660,9 +660,9 @@ rspamd_protocol_handle_headers(struct rspamd_task *task, IF_HEADER(USER_HEADER) { /* - * We must ignore User header in case of spamc, as SA has - * different meaning of this header - */ + * We must ignore User header in case of spamc, as SA has + * different meaning of this header + */ msg_debug_protocol("read user header, value: %T", hv_tok); if (!RSPAMD_TASK_IS_SPAMC(task)) { task->auth_user = rspamd_mempool_ftokdup(task->task_pool, @@ -708,6 +708,15 @@ rspamd_protocol_handle_headers(struct rspamd_task *task, task->flags |= RSPAMD_TASK_FLAG_NO_LOG; } } + IF_HEADER(LOG_TAG_HEADER) + { + msg_debug_protocol("read log-tag header, value: %T", hv_tok); + /* Ensure that a tag is valid */ + if (rspamd_fast_utf8_validate(hv_tok->begin, hv_tok->len) == 0) { + memcpy(task->task_pool->tag.uid, hv_tok->begin, + MIN(hv_tok->len, sizeof(task->task_pool->tag.uid))); + } + } break; case 'm': case 'M': @@ -752,9 +761,9 @@ rspamd_protocol_handle_headers(struct rspamd_task *task, default: msg_debug_protocol("generic header: %T", hn_tok); break; - } + } - rspamd_task_add_request_header (task, hn_tok, hv_tok); + rspamd_task_add_request_header (task, hn_tok, hv_tok); } }); /* End of kh_foreach_value */ diff --git a/src/libserver/protocol_internal.h b/src/libserver/protocol_internal.h index 7a70ccef0..e55e54851 100644 --- a/src/libserver/protocol_internal.h +++ b/src/libserver/protocol_internal.h @@ -78,6 +78,7 @@ extern "C" { #define HOSTNAME_HEADER "Hostname" #define DELIVER_TO_HEADER "Deliver-To" #define NO_LOG_HEADER "Log" +#define LOG_TAG_HEADER "Log-Tag" #define MLEN_HEADER "Message-Length" #define USER_AGENT_HEADER "User-Agent" #define MTA_TAG_HEADER "MTA-Tag" diff --git a/src/libserver/spf.c b/src/libserver/spf.c index 32c020bf3..562222042 100644 --- a/src/libserver/spf.c +++ b/src/libserver/spf.c @@ -451,6 +451,9 @@ rspamd_spf_process_reference(struct spf_resolved *target, target->flags |= RSPAMD_SPF_RESOLVED_NA; continue; } + if (cur->flags & RSPAMD_SPF_FLAG_PLUSALL) { + target->flags |= RSPAMD_SPF_RESOLVED_PLUSALL; + } if (cur->flags & RSPAMD_SPF_FLAG_INVALID) { /* Ignore invalid elements */ continue; @@ -1418,7 +1421,7 @@ parse_spf_all(struct spf_record *rec, struct spf_addr *addr) /* Disallow +all */ if (addr->mech == SPF_PASS) { - addr->flags |= RSPAMD_SPF_FLAG_INVALID; + addr->flags |= RSPAMD_SPF_FLAG_PLUSALL; msg_notice_spf("domain %s allows any SPF (+all), ignore SPF record completely", rec->sender_domain); } diff --git a/src/libserver/spf.h b/src/libserver/spf.h index cc0ee4c05..b89dc4d0e 100644 --- a/src/libserver/spf.h +++ b/src/libserver/spf.h @@ -77,6 +77,7 @@ typedef enum spf_action_e { #define RSPAMD_SPF_FLAG_PERMFAIL (1u << 10u) #define RSPAMD_SPF_FLAG_RESOLVED (1u << 11u) #define RSPAMD_SPF_FLAG_CACHED (1u << 12u) +#define RSPAMD_SPF_FLAG_PLUSALL (1u << 13u) /** Default SPF limits for avoiding abuse **/ #define SPF_MAX_NESTING 10 @@ -104,6 +105,7 @@ enum rspamd_spf_resolved_flags { RSPAMD_SPF_RESOLVED_TEMP_FAILED = (1u << 0u), RSPAMD_SPF_RESOLVED_PERM_FAILED = (1u << 1u), RSPAMD_SPF_RESOLVED_NA = (1u << 2u), + RSPAMD_SPF_RESOLVED_PLUSALL = (1u << 3u), }; struct spf_resolved { diff --git a/src/libserver/symcache/symcache_runtime.cxx b/src/libserver/symcache/symcache_runtime.cxx index dc7066b32..ddfbdf1ae 100644 --- a/src/libserver/symcache/symcache_runtime.cxx +++ b/src/libserver/symcache/symcache_runtime.cxx @@ -333,8 +333,8 @@ auto symcache_runtime::process_pre_postfilters(struct rspamd_task *task, */ if (stage != RSPAMD_TASK_STAGE_IDEMPOTENT && !(item->flags & SYMBOL_TYPE_IGNORE_PASSTHROUGH)) { - if (check_metric_limit(task)) { - msg_debug_cache_task_lambda("task has already the result being set, ignore further checks"); + if (check_process_status(task) == check_status::passthrough) { + msg_debug_cache_task_lambda("task has already the passthrough result being set, ignore further checks"); return true; } @@ -407,13 +407,20 @@ auto symcache_runtime::process_filters(struct rspamd_task *task, symcache &cache break; } + auto check_result = check_process_status(task); + if (!(item->flags & (SYMBOL_TYPE_FINE | SYMBOL_TYPE_IGNORE_PASSTHROUGH))) { - if (has_passtrough || check_metric_limit(task)) { - msg_debug_cache_task_lambda("task has already the result being set, ignore further checks"); + if (has_passtrough || check_result == check_status::passthrough) { + msg_debug_cache_task_lambda("task has already the passthrough result being set, ignore further checks"); has_passtrough = true; /* Skip this item */ continue; } + else if (check_result == check_status::limit_reached) { + msg_debug_cache_task_lambda("task has already the limit reached result being set, ignore further checks"); + /* Skip this item */ + continue; + } } auto dyn_item = &dynamic_items[idx]; @@ -531,19 +538,8 @@ auto symcache_runtime::process_symbol(struct rspamd_task *task, symcache &cache, return true; } -auto symcache_runtime::check_metric_limit(struct rspamd_task *task) -> bool +auto symcache_runtime::check_process_status(struct rspamd_task *task) -> symcache_runtime::check_status { - if (task->flags & RSPAMD_TASK_FLAG_PASS_ALL) { - return false; - } - - /* Check score limit */ - if (!std::isnan(lim)) { - if (task->result->score > lim) { - return true; - } - } - if (task->result->passthrough_result != nullptr) { /* We also need to check passthrough results */ auto *pr = task->result->passthrough_result; @@ -563,11 +559,22 @@ auto symcache_runtime::check_metric_limit(struct rspamd_task *task) -> bool } /* Immediately stop on non least passthrough action */ - return true; + return check_status::passthrough; } } - return false; + if (task->flags & RSPAMD_TASK_FLAG_PASS_ALL) { + return check_status::allow; + } + + /* Check score limit */ + if (!std::isnan(lim)) { + if (task->result->score > lim) { + return check_status::limit_reached; + } + } + + return check_status::allow; } auto symcache_runtime::check_item_deps(struct rspamd_task *task, symcache &cache, cache_item *item, diff --git a/src/libserver/symcache/symcache_runtime.hxx b/src/libserver/symcache/symcache_runtime.hxx index 7e4a41269..d1dc7ac24 100644 --- a/src/libserver/symcache/symcache_runtime.hxx +++ b/src/libserver/symcache/symcache_runtime.hxx @@ -60,6 +60,11 @@ class symcache_runtime { enabled = 1, disabled = 2, } slow_status; + enum class check_status { + allow, + limit_reached, + passthrough, + }; bool profile; double profile_start; @@ -77,7 +82,7 @@ class symcache_runtime { /* Specific stages of the processing */ auto process_pre_postfilters(struct rspamd_task *task, symcache &cache, int start_events, unsigned int stage) -> bool; auto process_filters(struct rspamd_task *task, symcache &cache, int start_events) -> bool; - auto check_metric_limit(struct rspamd_task *task) -> bool; + auto check_process_status(struct rspamd_task *task) -> check_status; auto check_item_deps(struct rspamd_task *task, symcache &cache, cache_item *item, cache_dynamic_item *dyn_item, bool check_only) -> bool; diff --git a/src/libstat/stat_process.c b/src/libstat/stat_process.c index ad976e713..5db3af6ce 100644 --- a/src/libstat/stat_process.c +++ b/src/libstat/stat_process.c @@ -509,6 +509,14 @@ rspamd_stat_classify(struct rspamd_task *task, lua_State *L, unsigned int stage, return ret; } + if (task->message == NULL) { + ret = RSPAMD_STAT_PROCESS_ERROR; + msg_err_task("trying to classify empty message"); + + task->processed_stages |= stage; + return ret; + } + if (stage == RSPAMD_TASK_STAGE_CLASSIFIERS_PRE) { /* Preprocess tokens */ rspamd_stat_preprocess(st_ctx, task, FALSE, FALSE); @@ -892,6 +900,18 @@ rspamd_stat_learn(struct rspamd_task *task, return ret; } + + if (task->message == NULL) { + ret = RSPAMD_STAT_PROCESS_ERROR; + if (err && *err == NULL) { + g_set_error(err, rspamd_stat_quark(), 500, + "Trying to learn an empty message"); + } + + task->processed_stages |= stage; + return ret; + } + if (stage == RSPAMD_TASK_STAGE_LEARN_PRE) { /* Process classifiers */ rspamd_stat_preprocess(st_ctx, task, TRUE, spam); diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index f5405f76d..e3f8b2e57 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -34,7 +34,11 @@ local function foo(task) -- do something end -rspamd_config:register_symbol('SYMBOL', 1.0, foo) +rspamd_config:register_symbol{ + name = 'SYMBOL', + score = 1.0, + callback = foo +} -- Get configuration local tab = rspamd_config:get_all_opt('module') -- get table for module's options @@ -1965,210 +1969,454 @@ lua_config_get_symbol_flags(lua_State *L) return 1; } -static int -lua_config_register_symbol(lua_State *L) +static bool +lua_config_register_symbol_from_table(lua_State *L, struct rspamd_config *cfg, + const char *name, int tbl_idx, int *id_out) { - LUA_TRACE_POINT; - struct rspamd_config *cfg = lua_check_config(L, 1); - const char *name = NULL, *type_str = NULL, - *description = NULL, *group = NULL; - double weight = 0, score = NAN, parent_float = NAN; - gboolean one_shot = FALSE; - int ret = -1, cbref = -1; - unsigned int type = 0, flags = 0; - int64_t parent = 0, priority = 0, nshots = 0; + unsigned int type = SYMBOL_TYPE_NORMAL, priority = 0; + double weight = 1.0, score = NAN; + const char *type_str, *group = NULL, *description = NULL; GArray *allowed_ids = NULL, *forbidden_ids = NULL; - GError *err = NULL; - int prev_top = lua_gettop(L); + int id, nshots, cb_ref, parent = -1; + unsigned int flags = 0; + gboolean optional = FALSE; - if (cfg) { - if (!rspamd_lua_parse_table_arguments(L, 2, &err, - RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT, - "name=S;weight=N;callback=F;type=S;priority=I;parent=D;" - "score=D;description=S;group=S;one_shot=B;nshots=I", - &name, &weight, &cbref, &type_str, - &priority, &parent_float, - &score, &description, &group, &one_shot, &nshots)) { - msg_err_config("bad arguments: %e", err); - g_error_free(err); - lua_settop(L, prev_top); + /* + * Table can have the following attributes: + * "callback" - should be a callback function + * "weight" - optional weight + * "priority" - optional priority + * "type" - optional type (normal, virtual, callback) + * "flags" - optional flags + * -- Metric options + * "score" - optional default score (overridden by metric) + * "group" - optional default group + * "one_shot" - optional one shot mode + * "description" - optional description + */ + lua_pushvalue(L, tbl_idx); /* Push table on top of the stack */ - return luaL_error(L, "invalid arguments"); - } + if (name == NULL) { + /* Try to resolve name */ + lua_pushstring(L, "name"); + lua_gettable(L, -2); - /* Deal with flags and ids */ - lua_pushstring(L, "flags"); - lua_gettable(L, 2); - if (lua_type(L, -1) == LUA_TSTRING) { - flags = lua_parse_symbol_flags(lua_tostring(L, -1)); - } - else if (lua_type(L, -1) == LUA_TTABLE) { - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - flags |= lua_parse_symbol_flags(lua_tostring(L, -1)); - } - } - lua_pop(L, 1); /* Clean flags */ + if (lua_type(L, -1) != LUA_TSTRING) { + lua_pop(L, 2); + luaL_error(L, "name is not specified"); - lua_pushstring(L, "allowed_ids"); - lua_gettable(L, 2); - if (lua_type(L, -1) == LUA_TSTRING) { - allowed_ids = rspamd_process_id_list(lua_tostring(L, -1)); + return false; } - else if (lua_type(L, -1) == LUA_TTABLE) { - allowed_ids = g_array_sized_new(FALSE, FALSE, sizeof(uint32_t), - rspamd_lua_table_size(L, -1)); - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - uint32_t v = lua_tointeger(L, -1); - g_array_append_val(allowed_ids, v); - } + else { + name = lua_tostring(L, -1); } + lua_pop(L, 1); + } - lua_pushstring(L, "forbidden_ids"); - lua_gettable(L, 2); - if (lua_type(L, -1) == LUA_TSTRING) { - forbidden_ids = rspamd_process_id_list(lua_tostring(L, -1)); + lua_pushstring(L, "callback"); + lua_gettable(L, -2); + + if (lua_type(L, -1) != LUA_TFUNCTION) { + cb_ref = -1; + } + else { + cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + lua_pop(L, 1); + + /* Optional fields */ + lua_pushstring(L, "weight"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TNUMBER) { + weight = lua_tonumber(L, -1); + } + lua_pop(L, 1); + + lua_pushstring(L, "priority"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TNUMBER) { + priority = lua_tointeger(L, -1); + } + lua_pop(L, 1); + + lua_pushstring(L, "optional"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TBOOLEAN) { + optional = lua_toboolean(L, -1); + } + lua_pop(L, 1); + + lua_pushstring(L, "type"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TSTRING) { + type_str = lua_tostring(L, -1); + } + else { + type_str = "normal"; + } + lua_pop(L, 1); + + type = lua_parse_symbol_type(type_str); + + if (!name && !(type & SYMBOL_TYPE_CALLBACK)) { + luaL_error(L, "no symbol name but type is not callback"); + + return false; + } + else if (!(type & SYMBOL_TYPE_VIRTUAL) && cb_ref == -1) { + luaL_error(L, "no callback for symbol %s", name); + + return false; + } + + lua_pushstring(L, "parent"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TNUMBER) { + parent = lua_tointeger(L, -1); + } + lua_pop(L, 1); + + + /* Deal with flags and ids */ + lua_pushstring(L, "flags"); + lua_gettable(L, -2); + if (lua_type(L, -1) == LUA_TSTRING) { + flags = lua_parse_symbol_flags(lua_tostring(L, -1)); + } + else if (lua_type(L, -1) == LUA_TTABLE) { + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + flags |= lua_parse_symbol_flags(lua_tostring(L, -1)); } - else if (lua_type(L, -1) == LUA_TTABLE) { - forbidden_ids = g_array_sized_new(FALSE, FALSE, sizeof(uint32_t), - rspamd_lua_table_size(L, -1)); - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - uint32_t v = lua_tointeger(L, -1); - g_array_append_val(forbidden_ids, v); - } + } + lua_pop(L, 1); /* Clean flags */ + + lua_pushstring(L, "allowed_ids"); + lua_gettable(L, -2); + if (lua_type(L, -1) == LUA_TSTRING) { + allowed_ids = rspamd_process_id_list(lua_tostring(L, -1)); + } + else if (lua_type(L, -1) == LUA_TTABLE) { + allowed_ids = g_array_sized_new(FALSE, FALSE, sizeof(uint32_t), + rspamd_lua_table_size(L, -1)); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + uint32_t v = lua_tointeger(L, -1); + g_array_append_val(allowed_ids, v); } - lua_pop(L, 1); + } + lua_pop(L, 1); - if (nshots == 0) { - nshots = cfg->default_max_shots; + lua_pushstring(L, "forbidden_ids"); + lua_gettable(L, -2); + if (lua_type(L, -1) == LUA_TSTRING) { + forbidden_ids = rspamd_process_id_list(lua_tostring(L, -1)); + } + else if (lua_type(L, -1) == LUA_TTABLE) { + forbidden_ids = g_array_sized_new(FALSE, FALSE, sizeof(uint32_t), + rspamd_lua_table_size(L, -1)); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + uint32_t v = lua_tointeger(L, -1); + g_array_append_val(forbidden_ids, v); } + } + lua_pop(L, 1); - type = lua_parse_symbol_type(type_str); + id = rspamd_register_symbol_fromlua(L, + cfg, + name, + cb_ref, + weight, + priority, + type | flags, + parent, + allowed_ids, forbidden_ids, + optional); - if (!name && !(type & SYMBOL_TYPE_CALLBACK)) { - lua_settop(L, prev_top); - return luaL_error(L, "no symbol name but type is not callback"); - } - else if (!(type & SYMBOL_TYPE_VIRTUAL) && cbref == -1) { - lua_settop(L, prev_top); - return luaL_error(L, "no callback for symbol %s", name); - } + if (allowed_ids) { + g_array_free(allowed_ids, TRUE); + } + + if (forbidden_ids) { + g_array_free(forbidden_ids, TRUE); + } + + if (id != -1) { + if (cb_ref != -1) { + /* Check for condition */ + lua_pushstring(L, "condition"); + lua_gettable(L, -2); - if (isnan(parent_float)) { - parent = -1; + if (lua_type(L, -1) == LUA_TFUNCTION) { + int condref; + + /* Here we pop function from the stack, so no lua_pop is required */ + condref = luaL_ref(L, LUA_REGISTRYINDEX); + g_assert(name != NULL); + rspamd_symcache_add_condition_delayed(cfg->cache, + name, L, condref); + } + else { + lua_pop(L, 1); + } } - else { - parent = parent_float; + + /* Check for augmentations */ + lua_pushstring(L, "augmentations"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TTABLE) { + + int aug_tbl_idx = lua_gettop(L); + for (lua_pushnil(L); lua_next(L, aug_tbl_idx); lua_pop(L, 1)) { + rspamd_symcache_add_symbol_augmentation(cfg->cache, id, + lua_tostring(L, -1), NULL); + } } - ret = rspamd_register_symbol_fromlua(L, - cfg, - name, - cbref, - weight == 0 ? 1.0 : weight, - priority, - type | flags, - parent, - allowed_ids, forbidden_ids, - FALSE); + lua_pop(L, 1); + } - if (allowed_ids) { - g_array_free(allowed_ids, TRUE); + /* + * Now check if a symbol has not been registered in any metric and + * insert default value if applicable + */ + struct rspamd_symbol *sym = g_hash_table_lookup(cfg->symbols, name); + if (sym == NULL || (sym->flags & RSPAMD_SYMBOL_FLAG_UNSCORED)) { + nshots = cfg->default_max_shots; + + lua_pushstring(L, "score"); + lua_gettable(L, -2); + if (lua_type(L, -1) == LUA_TNUMBER) { + score = lua_tonumber(L, -1); + + if (sym) { + /* Reset unscored flag */ + sym->flags &= ~RSPAMD_SYMBOL_FLAG_UNSCORED; + } } + lua_pop(L, 1); - if (forbidden_ids) { - g_array_free(forbidden_ids, TRUE); + lua_pushstring(L, "group"); + lua_gettable(L, -2); + if (lua_type(L, -1) == LUA_TSTRING) { + group = lua_tostring(L, -1); } + lua_pop(L, 1); + + if (!isnan(score) || group != NULL) { + lua_pushstring(L, "description"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TSTRING) { + description = lua_tostring(L, -1); + } + lua_pop(L, 1); + + lua_pushstring(L, "one_shot"); + lua_gettable(L, -2); - if (ret != -1) { - if (!isnan(score) || group) { - if (one_shot) { + if (lua_type(L, -1) == LUA_TBOOLEAN) { + if (lua_toboolean(L, -1)) { nshots = 1; } + } + lua_pop(L, 1); - rspamd_config_add_symbol(cfg, name, - score, description, group, flags, - 0, nshots); + lua_pushstring(L, "one_param"); + lua_gettable(L, -2); - lua_pushstring(L, "groups"); - lua_gettable(L, 2); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + if (lua_toboolean(L, -1)) { + flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM; + } + } + lua_pop(L, 1); - if (lua_istable(L, -1)) { - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - if (lua_isstring(L, -1)) { - rspamd_config_add_symbol_group(cfg, name, - lua_tostring(L, -1)); - } - else { - lua_settop(L, prev_top); - return luaL_error(L, "invalid groups element"); - } + /* + * Do not override the existing symbols (using zero priority), + * since we are defining default values here + */ + if (!isnan(score)) { + rspamd_config_add_symbol(cfg, name, score, + description, group, flags, 0, nshots); + } + else if (group) { + /* Add with zero score */ + rspamd_config_add_symbol(cfg, name, NAN, + description, group, flags, 0, nshots); + } + + lua_pushstring(L, "groups"); + lua_gettable(L, -2); + + if (lua_istable(L, -1)) { + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + if (lua_isstring(L, -1)) { + rspamd_config_add_symbol_group(cfg, name, + lua_tostring(L, -1)); + } + else { + lua_pop(L, 2); + luaL_error(L, "invalid groups element"); + + return false; } } + } - lua_pop(L, 1); + lua_pop(L, 1); + } + } + else { + /* Fill in missing fields from lua definition if they are not set */ + if (sym->description == NULL) { + lua_pushstring(L, "description"); + lua_gettable(L, -2); + + if (lua_type(L, -1) == LUA_TSTRING) { + description = lua_tostring(L, -1); } + lua_pop(L, 1); - lua_pushstring(L, "augmentations"); - lua_gettable(L, 2); + if (description) { + sym->description = rspamd_mempool_strdup(cfg->cfg_pool, description); + } + } - if (lua_type(L, -1) == LUA_TTABLE) { - int tbl_idx = lua_gettop(L); - for (lua_pushnil(L); lua_next(L, tbl_idx); lua_pop(L, 1)) { - size_t len; - const char *augmentation = lua_tolstring(L, -1, &len), *eqsign_pos; + /* If ungrouped and there is a group defined in lua, change the primary group + * Otherwise, add to the list of groups for this symbol. */ + lua_pushstring(L, "group"); + lua_gettable(L, -2); + if (lua_type(L, -1) == LUA_TSTRING) { + group = lua_tostring(L, -1); + } + lua_pop(L, 1); + if (group) { + if (sym->flags & RSPAMD_SYMBOL_FLAG_UNGROUPED) { + /* Unset the "ungrouped" group */ + sym->gr = NULL; + } + /* Add the group. If the symbol was ungrouped, this will + * clear RSPAMD_SYMBOL_FLAG_UNGROUPED from the flags. */ + rspamd_config_add_symbol_group(cfg, name, group); + } + } - /* Find `=` symbol and use it as a separator */ - eqsign_pos = memchr(augmentation, '=', len); - if (eqsign_pos != NULL && eqsign_pos + 1 < augmentation + len) { - rspamd_ftok_t tok; + /* Remove table from stack */ + lua_pop(L, 1); - tok.begin = augmentation; - tok.len = eqsign_pos - augmentation; - char *augentation_name = rspamd_ftokdup(&tok); + *id_out = id; - tok.begin = eqsign_pos + 1; - tok.len = (augmentation + len) - tok.begin; + return true; +} - char *augmentation_value = rspamd_ftokdup(&tok); +/* Legacy symbol registration */ +static bool +lua_config_register_symbol_legacy(lua_State *L, struct rspamd_config *cfg, int pos, int *id_out) +{ + const char *name = NULL, *type_str = NULL, + *description = NULL, *group = NULL; + double weight = 0, score = NAN, parent_float = NAN; + gboolean one_shot = FALSE; + int ret, cbref = -1; + unsigned int type = 0, flags = 0; + int64_t parent = 0, priority = 0, nshots = 0; - if (!rspamd_symcache_add_symbol_augmentation(cfg->cache, ret, - augentation_name, augmentation_value)) { - lua_settop(L, prev_top); - g_free(augmentation_value); - g_free(augentation_name); + GError *err = NULL; + if (!rspamd_lua_parse_table_arguments(L, pos, &err, + RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT, + "name=S;weight=N;callback=F;type=S;priority=I;parent=D;" + "score=D;description=S;group=S;one_shot=B;nshots=I", + &name, &weight, &cbref, &type_str, + &priority, &parent_float, + &score, &description, &group, &one_shot, &nshots)) { + msg_err_config("bad arguments: %e", err); + g_error_free(err); - return luaL_error(L, "unknown or invalid augmentation %s in symbol %s", - augmentation, name); - } + return false; + } - g_free(augmentation_value); - g_free(augentation_name); - } - else { - /* Just a value */ - if (!rspamd_symcache_add_symbol_augmentation(cfg->cache, ret, - augmentation, NULL)) { - lua_settop(L, prev_top); + type = lua_parse_symbol_type(type_str); - return luaL_error(L, "unknown augmentation %s in symbol %s", - augmentation, name); - } - } - } + if (!name && !(type & SYMBOL_TYPE_CALLBACK)) { + luaL_error(L, "no symbol name but type is not callback"); + + return false; + } + else if (!(type & SYMBOL_TYPE_VIRTUAL) && cbref == -1) { + luaL_error(L, "no callback for symbol %s", name); + + return false; + } + + if (isnan(parent_float)) { + parent = -1; + } + else { + parent = parent_float; + } + + ret = rspamd_register_symbol_fromlua(L, + cfg, + name, + cbref, + weight == 0 ? 1.0 : weight, + priority, + type | flags, + parent, + NULL, NULL, + FALSE); + + if (ret != -1) { + if (!isnan(score) || group) { + if (one_shot) { + nshots = 1; + } + if (nshots == 0) { + nshots = cfg->default_max_shots; } + + rspamd_config_add_symbol(cfg, name, score, + description, group, flags, 0, nshots); } + + *id_out = ret; + + return true; } - else { - lua_settop(L, prev_top); - return luaL_error(L, "invalid arguments"); + return false; +} + +static int +lua_config_register_symbol(lua_State *L) +{ + LUA_TRACE_POINT; + struct rspamd_config *cfg = lua_check_config(L, 1); + int id = -1; + + if (lua_type(L, 2) == LUA_TSTRING) { + if (lua_config_register_symbol_legacy(L, cfg, 2, &id)) { + lua_pushinteger(L, id); + + return 1; + } + else { + return luaL_error(L, "bad arguments"); + } } + else if (lua_config_register_symbol_from_table(L, cfg, NULL, 2, &id)) { + lua_pushinteger(L, id); - lua_settop(L, prev_top); - lua_pushinteger(L, ret); + return 1; + } - return 1; + return 0; } static int @@ -2655,10 +2903,7 @@ lua_config_newindex(lua_State *L) LUA_TRACE_POINT; struct rspamd_config *cfg = lua_check_config(L, 1); const char *name; - GArray *allowed_ids = NULL, *forbidden_ids = NULL; - int id, nshots; - unsigned int flags = 0; - gboolean optional = FALSE; + int id = -1; name = luaL_checkstring(L, 2); @@ -2679,291 +2924,14 @@ lua_config_newindex(lua_State *L) FALSE); } else if (lua_type(L, 3) == LUA_TTABLE) { - unsigned int type = SYMBOL_TYPE_NORMAL, priority = 0; - int idx; - double weight = 1.0, score = NAN; - const char *type_str, *group = NULL, *description = NULL; - - /* - * Table can have the following attributes: - * "callback" - should be a callback function - * "weight" - optional weight - * "priority" - optional priority - * "type" - optional type (normal, virtual, callback) - * "flags" - optional flags - * -- Metric options - * "score" - optional default score (overridden by metric) - * "group" - optional default group - * "one_shot" - optional one shot mode - * "description" - optional description - */ - lua_pushvalue(L, 3); - lua_pushstring(L, "callback"); - lua_gettable(L, -2); - - if (lua_type(L, -1) != LUA_TFUNCTION) { - lua_pop(L, 2); - msg_info_config("cannot find callback definition for %s", - name); - return 0; - } - idx = luaL_ref(L, LUA_REGISTRYINDEX); - - /* Optional fields */ - lua_pushstring(L, "weight"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TNUMBER) { - weight = lua_tonumber(L, -1); - } - lua_pop(L, 1); - - lua_pushstring(L, "priority"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TNUMBER) { - priority = lua_tointeger(L, -1); - } - lua_pop(L, 1); - - lua_pushstring(L, "optional"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TBOOLEAN) { - optional = lua_toboolean(L, -1); - } - lua_pop(L, 1); - - lua_pushstring(L, "type"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TSTRING) { - type_str = lua_tostring(L, -1); - type = lua_parse_symbol_type(type_str); - } - lua_pop(L, 1); - - /* Deal with flags and ids */ - lua_pushstring(L, "flags"); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TSTRING) { - flags = lua_parse_symbol_flags(lua_tostring(L, -1)); - } - else if (lua_type(L, -1) == LUA_TTABLE) { - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - flags |= lua_parse_symbol_flags(lua_tostring(L, -1)); - } - } - lua_pop(L, 1); /* Clean flags */ - - lua_pushstring(L, "allowed_ids"); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TSTRING) { - allowed_ids = rspamd_process_id_list(lua_tostring(L, -1)); - } - else if (lua_type(L, -1) == LUA_TTABLE) { - allowed_ids = g_array_sized_new(FALSE, FALSE, sizeof(uint32_t), - rspamd_lua_table_size(L, -1)); - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - uint32_t v = lua_tointeger(L, -1); - g_array_append_val(allowed_ids, v); - } - } - lua_pop(L, 1); - - lua_pushstring(L, "forbidden_ids"); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TSTRING) { - forbidden_ids = rspamd_process_id_list(lua_tostring(L, -1)); - } - else if (lua_type(L, -1) == LUA_TTABLE) { - forbidden_ids = g_array_sized_new(FALSE, FALSE, sizeof(uint32_t), - rspamd_lua_table_size(L, -1)); - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - uint32_t v = lua_tointeger(L, -1); - g_array_append_val(forbidden_ids, v); - } - } - lua_pop(L, 1); - - id = rspamd_register_symbol_fromlua(L, - cfg, - name, - idx, - weight, - priority, - type | flags, - -1, - allowed_ids, forbidden_ids, - optional); - - if (allowed_ids) { - g_array_free(allowed_ids, TRUE); - } - - if (forbidden_ids) { - g_array_free(forbidden_ids, TRUE); - } - - if (id != -1) { - /* Check for condition */ - lua_pushstring(L, "condition"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TFUNCTION) { - int condref; - - /* Here we pop function from the stack, so no lua_pop is required */ - condref = luaL_ref(L, LUA_REGISTRYINDEX); - g_assert(name != NULL); - rspamd_symcache_add_condition_delayed(cfg->cache, - name, L, condref); - } - else { - lua_pop(L, 1); - } - - /* Check for augmentations */ - lua_pushstring(L, "augmentations"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TTABLE) { - - int tbl_idx = lua_gettop(L); - for (lua_pushnil(L); lua_next(L, tbl_idx); lua_pop(L, 1)) { - rspamd_symcache_add_symbol_augmentation(cfg->cache, id, - lua_tostring(L, -1), NULL); - } - } - - lua_pop(L, 1); - } - - /* - * Now check if a symbol has not been registered in any metric and - * insert default value if applicable - */ - struct rspamd_symbol *sym = g_hash_table_lookup(cfg->symbols, name); - if (sym == NULL || (sym->flags & RSPAMD_SYMBOL_FLAG_UNSCORED)) { - nshots = cfg->default_max_shots; - - lua_pushstring(L, "score"); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TNUMBER) { - score = lua_tonumber(L, -1); - - if (sym) { - /* Reset unscored flag */ - sym->flags &= ~RSPAMD_SYMBOL_FLAG_UNSCORED; - } - } - lua_pop(L, 1); - - lua_pushstring(L, "group"); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TSTRING) { - group = lua_tostring(L, -1); - } - lua_pop(L, 1); - - if (!isnan(score) || group != NULL) { - lua_pushstring(L, "description"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TSTRING) { - description = lua_tostring(L, -1); - } - lua_pop(L, 1); - - lua_pushstring(L, "one_shot"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TBOOLEAN) { - if (lua_toboolean(L, -1)) { - nshots = 1; - } - } - lua_pop(L, 1); - - lua_pushstring(L, "one_param"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TBOOLEAN) { - if (lua_toboolean(L, -1)) { - flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM; - } - } - lua_pop(L, 1); - - /* - * Do not override the existing symbols (using zero priority), - * since we are defining default values here - */ - if (!isnan(score)) { - rspamd_config_add_symbol(cfg, name, score, - description, group, flags, 0, nshots); - } - else if (group) { - /* Add with zero score */ - rspamd_config_add_symbol(cfg, name, NAN, - description, group, flags, 0, nshots); - } - - lua_pushstring(L, "groups"); - lua_gettable(L, -2); - - if (lua_istable(L, -1)) { - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - if (lua_isstring(L, -1)) { - rspamd_config_add_symbol_group(cfg, name, - lua_tostring(L, -1)); - } - else { - return luaL_error(L, "invalid groups element"); - } - } - } - - lua_pop(L, 1); - } - } - else { - /* Fill in missing fields from lua definition if they are not set */ - if (sym->description == NULL) { - lua_pushstring(L, "description"); - lua_gettable(L, -2); - - if (lua_type(L, -1) == LUA_TSTRING) { - description = lua_tostring(L, -1); - } - lua_pop(L, 1); - - if (description) { - sym->description = rspamd_mempool_strdup(cfg->cfg_pool, description); - } - } - - /* If ungrouped and there is a group defined in lua, change the primary group - * Otherwise, add to the list of groups for this symbol. */ - lua_pushstring(L, "group"); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TSTRING) { - group = lua_tostring(L, -1); - } - lua_pop(L, 1); - if (group) { - if (sym->flags & RSPAMD_SYMBOL_FLAG_UNGROUPED) { - /* Unset the "ungrouped" group */ - sym->gr = NULL; - } - /* Add the group. If the symbol was ungrouped, this will - * clear RSPAMD_SYMBOL_FLAG_UNGROUPED from the flags. */ - rspamd_config_add_symbol_group(cfg, name, group); - } + /* Table symbol */ + if (lua_config_register_symbol_from_table(L, cfg, name, 3, &id)) { + lua_pushinteger(L, id); + return 1; } - - /* Remove table from stack */ - lua_pop(L, 1); + } + else { + return luaL_error(L, "invalid value for symbol"); } } else { @@ -3941,6 +3909,8 @@ lua_config_get_groups(lua_State *L) lua_setfield(L, -2, "description"); lua_pushnumber(L, gr->max_score); lua_setfield(L, -2, "max_score"); + lua_pushnumber(L, gr->min_score); + lua_setfield(L, -2, "min_score"); lua_pushboolean(L, (gr->flags & RSPAMD_SYMBOL_GROUP_PUBLIC) != 0); lua_setfield(L, -2, "is_public"); /* TODO: maybe push symbols as well */ diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c index bad7d7024..1b9074f58 100644 --- a/src/lua/lua_cryptobox.c +++ b/src/lua/lua_cryptobox.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -257,7 +257,6 @@ lua_check_cryptobox_secretbox(lua_State *L, int pos) * Loads public key from base32 encoded file * @param {string} file filename to load * @param {string} type optional 'sign' or 'kex' for signing and encryption - * @param {string} alg optional 'default' or 'nist' for curve25519/nistp256 keys * @return {cryptobox_pubkey} new public key */ static int @@ -267,7 +266,6 @@ lua_cryptobox_pubkey_load(lua_State *L) struct rspamd_cryptobox_pubkey *pkey = NULL, **ppkey; const char *filename, *arg; int type = RSPAMD_KEYPAIR_SIGN; - int alg = RSPAMD_CRYPTOBOX_MODE_25519; unsigned char *map; gsize len; @@ -293,19 +291,8 @@ lua_cryptobox_pubkey_load(lua_State *L) type = RSPAMD_KEYPAIR_KEX; } } - if (lua_type(L, 3) == LUA_TSTRING) { - /* algorithm */ - arg = lua_tostring(L, 3); - - if (strcmp(arg, "default") == 0 || strcmp(arg, "curve25519") == 0) { - type = RSPAMD_CRYPTOBOX_MODE_25519; - } - else if (strcmp(arg, "nist") == 0) { - type = RSPAMD_CRYPTOBOX_MODE_NIST; - } - } - pkey = rspamd_pubkey_from_base32(map, len, type, alg); + pkey = rspamd_pubkey_from_base32(map, len, type); if (pkey == NULL) { msg_err("cannot open pubkey from file: %s", filename); @@ -333,7 +320,6 @@ lua_cryptobox_pubkey_load(lua_State *L) * Loads public key from base32 encoded string * @param {base32 string} base32 string with the key * @param {string} type optional 'sign' or 'kex' for signing and encryption - * @param {string} alg optional 'default' or 'nist' for curve25519/nistp256 keys * @return {cryptobox_pubkey} new public key */ static int @@ -344,7 +330,6 @@ lua_cryptobox_pubkey_create(lua_State *L) const char *buf, *arg; gsize len; int type = RSPAMD_KEYPAIR_SIGN; - int alg = RSPAMD_CRYPTOBOX_MODE_25519; buf = luaL_checklstring(L, 1, &len); if (buf != NULL) { @@ -359,19 +344,8 @@ lua_cryptobox_pubkey_create(lua_State *L) type = RSPAMD_KEYPAIR_KEX; } } - if (lua_type(L, 3) == LUA_TSTRING) { - /* algorithm */ - arg = lua_tostring(L, 3); - - if (strcmp(arg, "default") == 0 || strcmp(arg, "curve25519") == 0) { - type = RSPAMD_CRYPTOBOX_MODE_25519; - } - else if (strcmp(arg, "nist") == 0) { - type = RSPAMD_CRYPTOBOX_MODE_NIST; - } - } - pkey = rspamd_pubkey_from_base32(buf, len, type, alg); + pkey = rspamd_pubkey_from_base32(buf, len, type); if (pkey == NULL) { msg_err("cannot load pubkey from string"); @@ -477,7 +451,6 @@ lua_cryptobox_keypair_load(lua_State *L) * @function rspamd_cryptobox_keypair.create([type='encryption'[, alg='curve25519']]) * Generates new keypair * @param {string} type type of keypair: 'encryption' (default) or 'sign' - * @param {string} alg algorithm of keypair: 'curve25519' (default) or 'nist' * @return {cryptobox_keypair} new keypair */ static int @@ -486,7 +459,6 @@ lua_cryptobox_keypair_create(lua_State *L) LUA_TRACE_POINT; struct rspamd_cryptobox_keypair *kp, **pkp; enum rspamd_cryptobox_keypair_type type = RSPAMD_KEYPAIR_KEX; - enum rspamd_cryptobox_mode alg = RSPAMD_CRYPTOBOX_MODE_25519; if (lua_isstring(L, 1)) { const char *str = lua_tostring(L, 1); @@ -502,21 +474,7 @@ lua_cryptobox_keypair_create(lua_State *L) } } - if (lua_isstring(L, 2)) { - const char *str = lua_tostring(L, 2); - - if (strcmp(str, "nist") == 0 || strcmp(str, "openssl") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_NIST; - } - else if (strcmp(str, "curve25519") == 0 || strcmp(str, "default") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_25519; - } - else { - return luaL_error(L, "invalid keypair algorithm: %s", str); - } - } - - kp = rspamd_keypair_new(type, alg); + kp = rspamd_keypair_new(type); pkp = lua_newuserdata(L, sizeof(gpointer)); *pkp = kp; @@ -606,12 +564,7 @@ lua_cryptobox_keypair_get_alg(lua_State *L) struct rspamd_cryptobox_keypair *kp = lua_check_cryptobox_keypair(L, 1); if (kp) { - if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) { - lua_pushstring(L, "curve25519"); - } - else { - lua_pushstring(L, "nist"); - } + lua_pushstring(L, "curve25519"); } else { return luaL_error(L, "invalid arguments"); @@ -636,7 +589,7 @@ lua_cryptobox_keypair_get_pk(lua_State *L) if (kp) { data = rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_PK, &dlen); - pk = rspamd_pubkey_from_bin(data, dlen, kp->type, kp->alg); + pk = rspamd_pubkey_from_bin(data, dlen, kp->type); if (pk == NULL) { return luaL_error(L, "invalid keypair"); @@ -654,7 +607,7 @@ lua_cryptobox_keypair_get_pk(lua_State *L) } /*** - * @function rspamd_cryptobox_signature.load(file, [alg = 'curve25519']) + * @function rspamd_cryptobox_signature.load(file) * Loads signature from raw file * @param {string} file filename to load * @return {cryptobox_signature} new signature @@ -668,7 +621,6 @@ lua_cryptobox_signature_load(lua_State *L) gpointer data; int fd; struct stat st; - enum rspamd_cryptobox_mode alg = RSPAMD_CRYPTOBOX_MODE_25519; filename = luaL_checkstring(L, 1); if (filename != NULL) { @@ -686,22 +638,6 @@ lua_cryptobox_signature_load(lua_State *L) lua_pushnil(L); } else { - if (lua_isstring(L, 2)) { - const char *str = lua_tostring(L, 2); - - if (strcmp(str, "nist") == 0 || strcmp(str, "openssl") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_NIST; - } - else if (strcmp(str, "curve25519") == 0 || strcmp(str, "default") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_25519; - } - else { - munmap(data, st.st_size); - close(fd); - - return luaL_error(L, "invalid keypair algorithm: %s", str); - } - } if (st.st_size > 0) { sig = rspamd_fstring_new_init(data, st.st_size); psig = lua_newuserdata(L, sizeof(rspamd_fstring_t *)); @@ -711,7 +647,7 @@ lua_cryptobox_signature_load(lua_State *L) else { msg_err("size of %s mismatches: %d while %d is expected", filename, (int) st.st_size, - rspamd_cryptobox_signature_bytes(alg)); + crypto_sign_bytes()); lua_pushnil(L); } @@ -821,7 +757,7 @@ lua_cryptobox_signature_create(lua_State *L) } if (data != NULL) { - if (dlen == rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519)) { + if (dlen == crypto_sign_bytes()) { sig = rspamd_fstring_new_init(data, dlen); psig = lua_newuserdata(L, sizeof(rspamd_fstring_t *)); rspamd_lua_setclass(L, rspamd_cryptobox_signature_classname, -1); @@ -1723,7 +1659,7 @@ lua_cryptobox_hash_gc(lua_State *L) } /*** - * @function rspamd_cryptobox.verify_memory(pk, sig, data, [alg = 'curve25519']) + * @function rspamd_cryptobox.verify_memory(pk, sig, data) * Check memory using specified cryptobox key and signature * @param {pubkey} pk public key to verify * @param {sig} signature to check @@ -1738,7 +1674,6 @@ lua_cryptobox_verify_memory(lua_State *L) rspamd_fstring_t *signature; struct rspamd_lua_text *t; const char *data; - enum rspamd_cryptobox_mode alg = RSPAMD_CRYPTOBOX_MODE_25519; gsize len; int ret; @@ -1759,23 +1694,9 @@ lua_cryptobox_verify_memory(lua_State *L) data = luaL_checklstring(L, 3, &len); } - if (lua_isstring(L, 4)) { - const char *str = lua_tostring(L, 4); - - if (strcmp(str, "nist") == 0 || strcmp(str, "openssl") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_NIST; - } - else if (strcmp(str, "curve25519") == 0 || strcmp(str, "default") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_25519; - } - else { - return luaL_error(L, "invalid algorithm: %s", str); - } - } - if (pk != NULL && signature != NULL && data != NULL) { ret = rspamd_cryptobox_verify(signature->str, signature->len, data, len, - rspamd_pubkey_get_pk(pk, NULL), alg); + rspamd_pubkey_get_pk(pk, NULL)); if (ret) { lua_pushboolean(L, 1); @@ -1792,7 +1713,7 @@ lua_cryptobox_verify_memory(lua_State *L) } /*** - * @function rspamd_cryptobox.verify_file(pk, sig, file, [alg = 'curve25519']) + * @function rspamd_cryptobox.verify_file(pk, sig, file) * Check file using specified cryptobox key and signature * @param {pubkey} pk public key to verify * @param {sig} signature to check @@ -1807,7 +1728,6 @@ lua_cryptobox_verify_file(lua_State *L) struct rspamd_cryptobox_pubkey *pk; rspamd_fstring_t *signature; unsigned char *map = NULL; - enum rspamd_cryptobox_mode alg = RSPAMD_CRYPTOBOX_MODE_25519; gsize len; int ret; @@ -1815,26 +1735,12 @@ lua_cryptobox_verify_file(lua_State *L) signature = lua_check_cryptobox_sign(L, 2); fname = luaL_checkstring(L, 3); - if (lua_isstring(L, 4)) { - const char *str = lua_tostring(L, 4); - - if (strcmp(str, "nist") == 0 || strcmp(str, "openssl") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_NIST; - } - else if (strcmp(str, "curve25519") == 0 || strcmp(str, "default") == 0) { - alg = RSPAMD_CRYPTOBOX_MODE_25519; - } - else { - return luaL_error(L, "invalid algorithm: %s", str); - } - } - map = rspamd_file_xmap(fname, PROT_READ, &len, TRUE); if (map != NULL && pk != NULL && signature != NULL) { ret = rspamd_cryptobox_verify(signature->str, signature->len, map, len, - rspamd_pubkey_get_pk(pk, NULL), alg); + rspamd_pubkey_get_pk(pk, NULL)); if (ret) { lua_pushboolean(L, 1); @@ -1896,12 +1802,11 @@ lua_cryptobox_sign_memory(lua_State *L) return luaL_error(L, "invalid arguments"); } - sig = rspamd_fstring_sized_new(rspamd_cryptobox_signature_bytes( - rspamd_keypair_alg(kp))); + sig = rspamd_fstring_sized_new(crypto_sign_bytes()); unsigned long long siglen = sig->len; rspamd_cryptobox_sign(sig->str, &siglen, data, - len, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL), rspamd_keypair_alg(kp)); + len, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL)); sig->len = siglen; psig = lua_newuserdata(L, sizeof(void *)); @@ -1942,13 +1847,12 @@ lua_cryptobox_sign_file(lua_State *L) lua_pushnil(L); } else { - sig = rspamd_fstring_sized_new(rspamd_cryptobox_signature_bytes( - rspamd_keypair_alg(kp))); + sig = rspamd_fstring_sized_new(crypto_sign_bytes()); unsigned long long siglen = sig->len; rspamd_cryptobox_sign(sig->str, &siglen, data, - len, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL), rspamd_keypair_alg(kp)); + len, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL)); sig->len = siglen; psig = lua_newuserdata(L, sizeof(void *)); @@ -1961,7 +1865,7 @@ lua_cryptobox_sign_file(lua_State *L) } /*** - * @function rspamd_cryptobox.encrypt_memory(kp, data[, nist=false]) + * @function rspamd_cryptobox.encrypt_memory(kp, data) * Encrypt data using specified keypair/pubkey * @param {keypair|string} kp keypair or pubkey in base32 to use * @param {string|text} data @@ -1993,8 +1897,7 @@ lua_cryptobox_encrypt_memory(lua_State *L) gsize blen; b32 = lua_tolstring(L, 1, &blen); - pk = rspamd_pubkey_from_base32(b32, blen, RSPAMD_KEYPAIR_KEX, - lua_toboolean(L, 3) ? RSPAMD_CRYPTOBOX_MODE_NIST : RSPAMD_CRYPTOBOX_MODE_25519); + pk = rspamd_pubkey_from_base32(b32, blen, RSPAMD_KEYPAIR_KEX); owned_pk = true; } @@ -2063,7 +1966,7 @@ err: } /*** - * @function rspamd_cryptobox.encrypt_file(kp|pk_string, filename[, nist=false]) + * @function rspamd_cryptobox.encrypt_file(kp|pk_string, filename) * Encrypt data using specified keypair/pubkey * @param {keypair|string} kp keypair or pubkey in base32 to use * @param {string} filename @@ -2096,8 +1999,7 @@ lua_cryptobox_encrypt_file(lua_State *L) gsize blen; b32 = lua_tolstring(L, 1, &blen); - pk = rspamd_pubkey_from_base32(b32, blen, RSPAMD_KEYPAIR_KEX, - lua_toboolean(L, 3) ? RSPAMD_CRYPTOBOX_MODE_NIST : RSPAMD_CRYPTOBOX_MODE_25519); + pk = rspamd_pubkey_from_base32(b32, blen, RSPAMD_KEYPAIR_KEX); own_pk = true; } @@ -2658,11 +2560,11 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L) char *b64_data; gsize b64_len; - rspamd_cryptobox_keypair_sig(pk, sk, RSPAMD_CRYPTOBOX_MODE_25519); + rspamd_cryptobox_keypair_sig(pk, sk); /* Process private key */ b64_data = rspamd_encode_base64(sk, - rspamd_cryptobox_sk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519), + crypto_sign_secretkeybytes(), -1, &b64_len); priv_out = lua_newuserdata(L, sizeof(*priv_out)); @@ -2673,7 +2575,7 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L) /* Process public key */ b64_data = rspamd_encode_base64(pk, - rspamd_cryptobox_pk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519), + crypto_sign_publickeybytes(), -1, &b64_len); pub_out = lua_newuserdata(L, sizeof(*pub_out)); @@ -2691,7 +2593,7 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L) char *b64_data; gsize b64_len; - rspamd_cryptobox_keypair_sig(pk, sk, RSPAMD_CRYPTOBOX_MODE_25519); + rspamd_cryptobox_keypair_sig(pk, sk); /* Process private key */ b64_data = rspamd_encode_base64(sk, @@ -2706,7 +2608,7 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L) /* Process public key */ b64_data = rspamd_encode_base64(pk, - rspamd_cryptobox_pk_sig_bytes(RSPAMD_CRYPTOBOX_MODE_25519), + crypto_sign_publickeybytes(), -1, &b64_len); pub_out = lua_newuserdata(L, sizeof(*pub_out)); diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c index 2032f7dc1..8ba612c1b 100644 --- a/src/lua/lua_http.c +++ b/src/lua/lua_http.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 Vsevolod Stakhov + * Copyright 2024 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -907,8 +907,7 @@ lua_http_request(lua_State *L) gsize inlen; in = lua_tolstring(L, -1, &inlen); - peer_key = rspamd_pubkey_from_base32(in, inlen, - RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); + peer_key = rspamd_pubkey_from_base32(in, inlen, RSPAMD_KEYPAIR_KEX); } lua_pop(L, 1); diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c index cce78ff2c..1cc2ce1bd 100644 --- a/src/lua/lua_map.c +++ b/src/lua/lua_map.c @@ -1293,8 +1293,7 @@ lua_map_set_sign_key(lua_State *L) pk_str = lua_tolstring(L, 2, &len); if (map && pk_str) { - pk = rspamd_pubkey_from_base32(pk_str, len, RSPAMD_KEYPAIR_SIGN, - RSPAMD_CRYPTOBOX_MODE_25519); + pk = rspamd_pubkey_from_base32(pk_str, len, RSPAMD_KEYPAIR_SIGN); if (!pk) { return luaL_error(L, "invalid pubkey string"); diff --git a/src/lua/lua_redis.c b/src/lua/lua_redis.c index f95abb577..d20c496ed 100644 --- a/src/lua/lua_redis.c +++ b/src/lua/lua_redis.c @@ -104,7 +104,7 @@ struct lua_redis_userdata { char *server; char log_tag[RSPAMD_LOG_ID_LEN + 1]; struct lua_redis_request_specific_userdata *specific; - double timeout; + ev_tstamp timeout; uint16_t port; uint16_t terminated; }; @@ -280,16 +280,23 @@ lua_redis_fin(void *arg) * @param code * @param ud */ +#ifdef __GNUC__ +__attribute__((format(printf, 1, 5))) +#endif static void lua_redis_push_error(const char *err, struct lua_redis_ctx *ctx, struct lua_redis_request_specific_userdata *sp_ud, - gboolean connected) + gboolean connected, + ...) { struct lua_redis_userdata *ud = sp_ud->c; struct lua_callback_state cbs; lua_State *L; + va_list ap; + va_start(ap, connected); + if (!(sp_ud->flags & (LUA_REDIS_SPECIFIC_REPLIED | LUA_REDIS_SPECIFIC_FINISHED))) { if (sp_ud->cbref != -1) { @@ -302,7 +309,7 @@ lua_redis_push_error(const char *err, lua_rawgeti(cbs.L, LUA_REGISTRYINDEX, sp_ud->cbref); /* String of error */ - lua_pushstring(cbs.L, err); + lua_pushvfstring(cbs.L, err, ap); /* Data is nil */ lua_pushnil(cbs.L); @@ -331,6 +338,8 @@ lua_redis_push_error(const char *err, lua_redis_fin(sp_ud); } } + + va_end(ap); } static void @@ -479,7 +488,7 @@ lua_redis_callback(redisAsyncContext *c, gpointer r, gpointer priv) lua_redis_push_data(reply, ctx, sp_ud); } else { - lua_redis_push_error(reply->str, ctx, sp_ud, TRUE); + lua_redis_push_error("%s", ctx, sp_ud, TRUE, reply->str); } } else { @@ -488,10 +497,10 @@ lua_redis_callback(redisAsyncContext *c, gpointer r, gpointer priv) } else { if (c->err == REDIS_ERR_IO) { - lua_redis_push_error(strerror(errno), ctx, sp_ud, TRUE); + lua_redis_push_error("%s", ctx, sp_ud, TRUE, strerror(errno)); } else { - lua_redis_push_error(c->errstr, ctx, sp_ud, TRUE); + lua_redis_push_error("%s", ctx, sp_ud, TRUE, c->errstr); } } } @@ -750,7 +759,7 @@ lua_redis_timeout(EV_P_ ev_timer *w, int revents) REDIS_RETAIN(ctx); msg_debug_lua_redis("timeout while querying redis server: %p, redis: %p", sp_ud, sp_ud->c->ctx); - lua_redis_push_error("timeout while connecting the server", ctx, sp_ud, TRUE); + lua_redis_push_error("timeout while connecting the server (%.2f sec)", ctx, sp_ud, TRUE, ud->timeout); if (sp_ud->c->ctx) { ac = sp_ud->c->ctx; diff --git a/src/lua/lua_rsa.c b/src/lua/lua_rsa.c index 0f67e91d1..0c56b223b 100644 --- a/src/lua/lua_rsa.c +++ b/src/lua/lua_rsa.c @@ -91,22 +91,22 @@ static const struct luaL_reg rsasignlib_m[] = { {"__gc", lua_rsa_signature_gc}, {NULL, NULL}}; -static RSA * +static EVP_PKEY * lua_check_rsa_pubkey(lua_State *L, int pos) { void *ud = rspamd_lua_check_udata(L, pos, rspamd_rsa_pubkey_classname); luaL_argcheck(L, ud != NULL, 1, "'rsa_pubkey' expected"); - return ud ? *((RSA **) ud) : NULL; + return ud ? *((EVP_PKEY **) ud) : NULL; } -static RSA * +static EVP_PKEY * lua_check_rsa_privkey(lua_State *L, int pos) { void *ud = rspamd_lua_check_udata(L, pos, rspamd_rsa_privkey_classname); luaL_argcheck(L, ud != NULL, 1, "'rsa_privkey' expected"); - return ud ? *((RSA **) ud) : NULL; + return ud ? *((EVP_PKEY **) ud) : NULL; } static rspamd_fstring_t * @@ -121,7 +121,7 @@ lua_check_rsa_sign(lua_State *L, int pos) static int lua_rsa_pubkey_load(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey = NULL, **ppkey; const char *filename; FILE *f; @@ -135,15 +135,15 @@ lua_rsa_pubkey_load(lua_State *L) lua_pushnil(L); } else { - if (!PEM_read_RSA_PUBKEY(f, &rsa, NULL, NULL)) { + if (!PEM_read_PUBKEY(f, &pkey, NULL, NULL)) { msg_err("cannot open pubkey from file: %s, %s", filename, ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_pubkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } fclose(f); } @@ -161,15 +161,14 @@ lua_rsa_privkey_save(lua_State *L) const char *type = "pem"; FILE *f; int ret; - - RSA *rsa = lua_check_rsa_privkey(L, 1); + EVP_PKEY *pkey = lua_check_rsa_privkey(L, 1); filename = luaL_checkstring(L, 2); if (lua_gettop(L) > 2) { type = luaL_checkstring(L, 3); } - if (rsa != NULL && filename != NULL) { + if (pkey != NULL && filename != NULL) { if (strcmp(filename, "-") == 0) { f = stdout; } @@ -189,10 +188,10 @@ lua_rsa_privkey_save(lua_State *L) } if (strcmp(type, "der") == 0) { - ret = i2d_RSAPrivateKey_fp(f, rsa); + ret = i2d_PrivateKey_fp(f, pkey); } else { - ret = PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL, NULL); + ret = PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL); } if (!ret) { @@ -223,7 +222,7 @@ lua_rsa_privkey_save(lua_State *L) static int lua_rsa_pubkey_create(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey, **ppkey; const char *buf; BIO *bp; @@ -231,15 +230,15 @@ lua_rsa_pubkey_create(lua_State *L) if (buf != NULL) { bp = BIO_new_mem_buf((void *) buf, -1); - if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) { + if (!PEM_read_bio_PUBKEY(bp, &pkey, NULL, NULL)) { msg_err("cannot parse pubkey: %s", ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_pubkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } BIO_free(bp); } @@ -252,10 +251,10 @@ lua_rsa_pubkey_create(lua_State *L) static int lua_rsa_pubkey_gc(lua_State *L) { - RSA *rsa = lua_check_rsa_pubkey(L, 1); + EVP_PKEY *pkey = lua_check_rsa_pubkey(L, 1); - if (rsa != NULL) { - RSA_free(rsa); + if (pkey != NULL) { + EVP_PKEY_free(pkey); } return 0; @@ -264,18 +263,18 @@ lua_rsa_pubkey_gc(lua_State *L) static int lua_rsa_pubkey_tostring(lua_State *L) { - RSA *rsa = lua_check_rsa_pubkey(L, 1); + EVP_PKEY *pkey = lua_check_rsa_pubkey(L, 1); - if (rsa != NULL) { + if (pkey != NULL) { BIO *pubout = BIO_new(BIO_s_mem()); const char *pubdata; gsize publen; - int rc = i2d_RSA_PUBKEY_bio(pubout, rsa); + int rc = i2d_PUBKEY_bio(pubout, pkey); if (rc != 1) { BIO_free(pubout); - return luaL_error(L, "i2d_RSA_PUBKEY_bio failed"); + return luaL_error(L, "i2d_PUBKEY_bio failed"); } publen = BIO_get_mem_data(pubout, &pubdata); @@ -292,7 +291,7 @@ lua_rsa_pubkey_tostring(lua_State *L) static int lua_rsa_privkey_load_file(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey = NULL, **ppkey; const char *filename; FILE *f; @@ -306,15 +305,15 @@ lua_rsa_privkey_load_file(lua_State *L) lua_pushnil(L); } else { - if (!PEM_read_RSAPrivateKey(f, &rsa, NULL, NULL)) { + if (!PEM_read_PrivateKey(f, &pkey, NULL, NULL)) { msg_err("cannot open private key from file: %s, %s", filename, ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } fclose(f); } @@ -328,7 +327,7 @@ lua_rsa_privkey_load_file(lua_State *L) static int lua_rsa_privkey_load_pem(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey = NULL, **ppkey; BIO *b; struct rspamd_lua_text *t; const char *data; @@ -351,15 +350,15 @@ lua_rsa_privkey_load_pem(lua_State *L) if (data != NULL) { b = BIO_new_mem_buf(data, len); - if (!PEM_read_bio_RSAPrivateKey(b, &rsa, NULL, NULL)) { + if (!PEM_read_bio_PrivateKey(b, &pkey, NULL, NULL)) { msg_err("cannot open private key from data, %s", ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } BIO_free(b); @@ -374,7 +373,7 @@ lua_rsa_privkey_load_pem(lua_State *L) static int lua_rsa_privkey_load_raw(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey = NULL, **ppkey; BIO *b; struct rspamd_lua_text *t; const char *data; @@ -396,17 +395,17 @@ lua_rsa_privkey_load_raw(lua_State *L) if (data != NULL) { b = BIO_new_mem_buf(data, len); - rsa = d2i_RSAPrivateKey_bio(b, NULL); + pkey = d2i_PrivateKey_bio(b, NULL); - if (rsa == NULL) { + if (pkey == NULL) { msg_err("cannot open private key from data, %s", ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } BIO_free(b); @@ -421,9 +420,8 @@ lua_rsa_privkey_load_raw(lua_State *L) static int lua_rsa_privkey_load_base64(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey = NULL, **ppkey; BIO *b; - EVP_PKEY *evp = NULL; struct rspamd_lua_text *t; const char *data; unsigned char *decoded; @@ -454,21 +452,18 @@ lua_rsa_privkey_load_base64(lua_State *L) b = BIO_new_mem_buf(decoded, dec_len); - if (d2i_PrivateKey_bio(b, &evp) != NULL) { - rsa = EVP_PKEY_get1_RSA(evp); - - if (rsa == NULL) { + if (d2i_PrivateKey_bio(b, &pkey) != NULL) { + if (pkey == NULL) { msg_err("cannot open RSA private key from data, %s", ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } - EVP_PKEY_free(evp); } else { msg_err("cannot open EVP private key from data, %s", @@ -489,7 +484,7 @@ lua_rsa_privkey_load_base64(lua_State *L) static int lua_rsa_privkey_create(lua_State *L) { - RSA *rsa = NULL, **prsa; + EVP_PKEY *pkey = NULL, **ppkey; const char *buf; BIO *bp; @@ -497,15 +492,15 @@ lua_rsa_privkey_create(lua_State *L) if (buf != NULL) { bp = BIO_new_mem_buf((void *) buf, -1); - if (!PEM_read_bio_RSAPrivateKey(bp, &rsa, NULL, NULL)) { + if (!PEM_read_bio_PrivateKey(bp, &pkey, NULL, NULL)) { msg_err("cannot parse private key: %s", ERR_error_string(ERR_get_error(), NULL)); lua_pushnil(L); } else { - prsa = lua_newuserdata(L, sizeof(RSA *)); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1); - *prsa = rsa; + *ppkey = pkey; } BIO_free(bp); } @@ -518,10 +513,10 @@ lua_rsa_privkey_create(lua_State *L) static int lua_rsa_privkey_gc(lua_State *L) { - RSA *rsa = lua_check_rsa_privkey(L, 1); + EVP_PKEY *pkey = lua_check_rsa_privkey(L, 1); - if (rsa != NULL) { - RSA_free(rsa); + if (pkey != NULL) { + EVP_PKEY_free(pkey); } return 0; @@ -699,19 +694,22 @@ lua_rsa_signature_base64(lua_State *L) static int lua_rsa_verify_memory(lua_State *L) { - RSA *rsa; + EVP_PKEY *pkey; rspamd_fstring_t *signature; const char *data; gsize sz; int ret; - rsa = lua_check_rsa_pubkey(L, 1); + pkey = lua_check_rsa_pubkey(L, 1); signature = lua_check_rsa_sign(L, 2); data = luaL_checklstring(L, 3, &sz); - if (rsa != NULL && signature != NULL && data != NULL) { - ret = RSA_verify(NID_sha256, data, sz, - signature->str, signature->len, rsa); + if (pkey != NULL && signature != NULL && data != NULL) { + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL); + g_assert(pctx != NULL); + g_assert(EVP_PKEY_verify_init(pctx) == 1); + + ret = EVP_PKEY_verify(pctx, signature->str, signature->len, data, sz); if (ret == 0) { lua_pushboolean(L, FALSE); @@ -722,6 +720,7 @@ lua_rsa_verify_memory(lua_State *L) else { lua_pushboolean(L, TRUE); } + EVP_PKEY_CTX_free(pctx); } else { lua_pushnil(L); @@ -743,22 +742,26 @@ lua_rsa_verify_memory(lua_State *L) static int lua_rsa_sign_memory(lua_State *L) { - RSA *rsa; + EVP_PKEY *pkey; rspamd_fstring_t *signature, **psig; const char *data; gsize sz; int ret; - rsa = lua_check_rsa_privkey(L, 1); + pkey = lua_check_rsa_privkey(L, 1); data = luaL_checklstring(L, 2, &sz); - if (rsa != NULL && data != NULL) { - signature = rspamd_fstring_sized_new(RSA_size(rsa)); + if (pkey != NULL && data != NULL) { + signature = rspamd_fstring_sized_new(EVP_PKEY_get_size(pkey)); + + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL); + g_assert(pctx != NULL); - unsigned int siglen = signature->len; - ret = RSA_sign(NID_sha256, data, sz, - signature->str, &siglen, rsa); + g_assert(EVP_PKEY_sign_init(pctx) == 1); + size_t slen = signature->allocated; + ret = EVP_PKEY_sign(pctx, signature->str, &slen, data, sz); + EVP_PKEY_CTX_free(pctx); if (ret != 1) { rspamd_fstring_free(signature); @@ -766,7 +769,7 @@ lua_rsa_sign_memory(lua_State *L) ERR_error_string(ERR_get_error(), NULL)); } else { - signature->len = siglen; + signature->len = slen; psig = lua_newuserdata(L, sizeof(rspamd_fstring_t *)); rspamd_lua_setclass(L, rspamd_rsa_signature_classname, -1); *psig = signature; @@ -783,7 +786,7 @@ static int lua_rsa_keypair(lua_State *L) { BIGNUM *e; - RSA *rsa, *pub_rsa, *priv_rsa, **prsa; + EVP_PKEY *pkey = NULL, *pub_pkey, *priv_pkey, **ppkey; int bits = lua_gettop(L) > 0 ? lua_tointeger(L, 1) : 1024; if (bits > 4096 || bits < 512) { @@ -791,21 +794,30 @@ lua_rsa_keypair(lua_State *L) } e = BN_new(); - rsa = RSA_new(); + g_assert(BN_set_word(e, RSA_F4) == 1); - g_assert(RSA_generate_key_ex(rsa, bits, e, NULL) == 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_rsa = RSAPrivateKey_dup(rsa); - prsa = lua_newuserdata(L, sizeof(RSA *)); + priv_pkey = EVP_PKEY_dup(pkey); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1); - *prsa = priv_rsa; + *ppkey = priv_pkey; - pub_rsa = RSAPublicKey_dup(rsa); - prsa = lua_newuserdata(L, sizeof(RSA *)); + pub_pkey = EVP_PKEY_dup(pkey); + ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *)); rspamd_lua_setclass(L, rspamd_rsa_pubkey_classname, -1); - *prsa = pub_rsa; + *ppkey = pub_pkey; - RSA_free(rsa); + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(pctx); BN_free(e); return 2; diff --git a/src/lua/lua_spf.c b/src/lua/lua_spf.c index 46e72202f..850ce2120 100644 --- a/src/lua/lua_spf.c +++ b/src/lua/lua_spf.c @@ -89,6 +89,8 @@ lua_load_spf(lua_State *L) lua_setfield(L, -2, "perm_fail"); lua_pushinteger(L, RSPAMD_SPF_FLAG_CACHED); lua_setfield(L, -2, "cached"); + lua_pushinteger(L, RSPAMD_SPF_RESOLVED_PLUSALL); + lua_setfield(L, -2, "plusall"); lua_setfield(L, -2, "flags"); @@ -368,6 +370,11 @@ spf_check_element(lua_State *L, struct spf_resolved *rec, struct spf_addr *addr, lua_pushinteger(L, RSPAMD_SPF_RESOLVED_TEMP_FAILED); lua_pushfstring(L, "%cany", spf_mech_char(addr->mech)); } + else if (rec->flags & RSPAMD_SPF_RESOLVED_PLUSALL) { + lua_pushboolean(L, false); + lua_pushinteger(L, RSPAMD_SPF_RESOLVED_PLUSALL); + lua_pushfstring(L, "%cany", spf_mech_char(addr->mech)); + } else { lua_pushboolean(L, true); lua_pushinteger(L, addr->mech); diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c index 21e24fc45..3968c01eb 100644 --- a/src/lua/lua_task.c +++ b/src/lua/lua_task.c @@ -1318,6 +1318,7 @@ static const struct luaL_reg tasklib_m[] = { LUA_INTERFACE_DEF(task, get_metric_threshold), LUA_INTERFACE_DEF(task, set_metric_score), LUA_INTERFACE_DEF(task, set_metric_subject), + {"set_subject", lua_task_set_metric_subject}, LUA_INTERFACE_DEF(task, learn), LUA_INTERFACE_DEF(task, set_settings), LUA_INTERFACE_DEF(task, get_settings), diff --git a/src/plugins/fuzzy_check.c b/src/plugins/fuzzy_check.c index a035eeaae..91b77c702 100644 --- a/src/plugins/fuzzy_check.c +++ b/src/plugins/fuzzy_check.c @@ -543,15 +543,13 @@ fuzzy_parse_rule(struct rspamd_config *cfg, const ucl_object_t *obj, k = ucl_object_tostring(value); if (k == NULL || (rule->peer_key = - rspamd_pubkey_from_base32(k, 0, RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519)) == NULL) { + rspamd_pubkey_from_base32(k, 0, RSPAMD_KEYPAIR_KEX)) == NULL) { msg_err_config("bad encryption key value: %s", k); return -1; } - rule->local_key = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX, - RSPAMD_CRYPTOBOX_MODE_25519); + rule->local_key = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX); } if ((value = ucl_object_lookup(obj, "learn_condition")) != NULL) { @@ -1334,8 +1332,7 @@ fuzzy_encrypt_cmd(struct fuzzy_rule *rule, rule->local_key, rule->peer_key); rspamd_cryptobox_encrypt_nm_inplace(data, datalen, hdr->nonce, rspamd_pubkey_get_nm(rule->peer_key, rule->local_key), - hdr->mac, - rspamd_pubkey_alg(rule->peer_key)); + hdr->mac); } static struct fuzzy_cmd_io * @@ -2209,8 +2206,7 @@ fuzzy_process_reply(unsigned char **pos, int *r, GPtrArray *req, sizeof(encrep.rep), encrep.hdr.nonce, rspamd_pubkey_get_nm(rule->peer_key, rule->local_key), - encrep.hdr.mac, - rspamd_pubkey_alg(rule->peer_key))) { + encrep.hdr.mac)) { msg_info("cannot decrypt reply"); return NULL; } @@ -2299,6 +2295,8 @@ fuzzy_insert_result(struct fuzzy_client_session *session, * Otherwise `value` means error code */ + msg_debug_fuzzy_check("got reply with probability %.2f and value %.2f", + (double) rep->v1.prob, (double) rep->v1.value); nval = fuzzy_normalize(rep->v1.value, weight); if (io) { diff --git a/src/plugins/lua/arc.lua b/src/plugins/lua/arc.lua index ff19aef4c..90e254e78 100644 --- a/src/plugins/lua/arc.lua +++ b/src/plugins/lua/arc.lua @@ -635,11 +635,21 @@ local function prepare_arc_selector(task, sel) end end + local function arc_result_from_ar(ar_header) + ar_header = ar_header or "" + for k, v in string.gmatch(ar_header, "(%w+)=(%w+)") do + if k == 'arc' then + return v + end + end + return nil + end + if settings.reuse_auth_results then local ar_header = task:get_header('Authentication-Results') if ar_header then - local arc_match = string.match(ar_header, 'arc=(%w+)') + local arc_match = arc_result_from_ar(ar_header) if arc_match then if arc_match == 'none' or arc_match == 'pass' then diff --git a/src/plugins/lua/gpt.lua b/src/plugins/lua/gpt.lua index 6adbce3bf..823dbd045 100644 --- a/src/plugins/lua/gpt.lua +++ b/src/plugins/lua/gpt.lua @@ -27,13 +27,11 @@ gpt { # Your key to access the API api_key = "xxx"; # Model name - model = "gpt-3.5-turbo"; + model = "gpt-4o-mini"; # Maximum tokens to generate max_tokens = 1000; # Temperature for sampling - temperature = 0.7; - # Top p for sampling - top_p = 0.9; + temperature = 0.0; # Timeout for requests timeout = 10s; # Prompt for the model (use default if not set) @@ -71,10 +69,9 @@ local default_symbols_to_except = { local settings = { type = 'openai', api_key = nil, - model = 'gpt-3.5-turbo', + model = 'gpt-4o-mini', max_tokens = 1000, - temperature = 0.7, - top_p = 0.9, + temperature = 0.0, timeout = 10, prompt = nil, condition = nil, @@ -97,11 +94,11 @@ local function default_condition(task) local action = result.action if action == 'reject' and result.npositive > 1 then - return true, 'already decided as spam' + return false, 'already decided as spam' end if action == 'no action' and score < 0 then - return true, 'negative score, already decided as ham' + return false, 'negative score, already decided as ham' end end -- We also exclude some symbols @@ -109,10 +106,12 @@ local function default_condition(task) if task:has_symbol(s) then if required_weight > 0 then -- Also check score - local sym = task:get_symbol(s) + local sym = task:get_symbol(s) or E -- Must exist as we checked it before with `has_symbol` - if math.abs(sym.weight) >= required_weight then - return false, 'skip as "' .. s .. '" is found (weight: ' .. sym.weight .. ')' + if sym.weight then + if math.abs(sym.weight) >= required_weight then + return false, 'skip as "' .. s .. '" is found (weight: ' .. sym.weight .. ')' + end end lua_util.debugm(N, task, 'symbol %s has weight %s, but required %s', s, sym.weight, required_weight) @@ -195,6 +194,18 @@ local function default_conversion(task, input) if type(reply) == 'table' and reply.probability then local spam_score = tonumber(reply.probability) + + if not spam_score then + -- Maybe we need GPT to convert GPT reply here? + if reply.probability == "high" then + spam_score = 0.9 + elseif reply.probability == "low" then + spam_score = 0.1 + else + rspamd_logger.infox("cannot convert to spam probability: %s", reply.probability) + end + end + if type(reply.usage) == 'table' then rspamd_logger.infox(task, 'usage: %s tokens', reply.usage.total_tokens) end @@ -276,7 +287,7 @@ local function openai_gpt_check(task) model = settings.model, max_tokens = settings.max_tokens, temperature = settings.temperature, - top_p = settings.top_p, + response_format = { type = "json_object" }, messages = { { role = 'system', @@ -348,8 +359,8 @@ if opts then end if not settings.prompt then - settings.prompt = "You will be provided with the email message, " .. - "and your task is to classify its probability to be spam, " .. + settings.prompt = "You will be provided with the email message, subject, from and url domains, " .. + "and your task is to evaluate the probability to be spam as number from 0 to 1, " .. "output result as JSON with 'probability' field." end diff --git a/src/plugins/lua/history_redis.lua b/src/plugins/lua/history_redis.lua index 3365b30cd..fff9f46b3 100644 --- a/src/plugins/lua/history_redis.lua +++ b/src/plugins/lua/history_redis.lua @@ -21,8 +21,8 @@ if confighelp then redis_history { # History key name key_prefix = 'rs_history{{HOSTNAME}}{{COMPRESS}}'; - # History expire in seconds - expire = 0; + # Expire in seconds for inactive keys, default to 5 days + expire = 432000; # History rows limit nrows = 200; # Use zstd compression when storing data in redis diff --git a/src/plugins/lua/known_senders.lua b/src/plugins/lua/known_senders.lua index 6d57acea3..5cb2ddcf5 100644 --- a/src/plugins/lua/known_senders.lua +++ b/src/plugins/lua/known_senders.lua @@ -18,6 +18,7 @@ limitations under the License. local rspamd_logger = require "rspamd_logger" local N = 'known_senders' +local E = {} local lua_util = require "lua_util" local lua_redis = require "lua_redis" local lua_maps = require "lua_maps" @@ -258,7 +259,7 @@ local function verify_local_replies_set(task) return nil end - local replies_recipients = task:get_recipients('mime') + local replies_recipients = task:get_recipients('mime') or E local replies_sender_string = lua_util.maybe_obfuscate_string(tostring(replies_sender), settings, settings.sender_prefix) diff --git a/src/plugins/lua/once_received.lua b/src/plugins/lua/once_received.lua index 2a5552ab9..5c5ff7986 100644 --- a/src/plugins/lua/once_received.lua +++ b/src/plugins/lua/once_received.lua @@ -19,10 +19,7 @@ if confighelp then end -- 0 or 1 received: = spam - local symbol = 'ONCE_RECEIVED' -local symbol_rdns = 'RDNS_NONE' -local symbol_rdns_dnsfail = 'RDNS_DNSFAIL' local symbol_mx = 'DIRECT_TO_MX' -- Symbol for strict checks local symbol_strict = nil @@ -47,54 +44,6 @@ local function check_quantity_received (task) return not h['flags']['artificial'] end, recvh)) - local function recv_dns_cb(_, to_resolve, results, err) - if err and (err ~= 'requested record is not found' and err ~= 'no records with this name') then - rspamd_logger.errx(task, 'error looking up %s: %s', to_resolve, err) - task:insert_result(symbol_rdns_dnsfail, 1.0) - end - - if not results then - if nreceived <= 1 then - task:insert_result(symbol, 1) - -- Avoid strict symbol inserting as the remaining symbols have already - -- quote a significant weight, so a message could be rejected by just - -- this property. - --task:insert_result(symbol_strict, 1) - -- Check for MUAs - local ua = task:get_header('User-Agent') - local xm = task:get_header('X-Mailer') - if (ua or xm) then - task:insert_result(symbol_mx, 1, (ua or xm)) - end - end - task:insert_result(symbol_rdns, 1) - else - rspamd_logger.infox(task, 'source hostname has not been passed to Rspamd from MTA, ' .. - 'but we could resolve source IP address PTR %s as "%s"', - to_resolve, results[1]) - task:set_hostname(results[1]) - - if good_hosts then - for _, gh in ipairs(good_hosts) do - if string.find(results[1], gh) then - return - end - end - end - - if nreceived <= 1 then - task:insert_result(symbol, 1) - for _, h in ipairs(bad_hosts) do - if string.find(results[1], h) then - - task:insert_result(symbol_strict, 1, h) - return - end - end - end - end - end - local task_ip = task:get_ip() if ((not check_authed and task:get_user()) or @@ -110,13 +59,39 @@ local function check_quantity_received (task) local hn = task:get_hostname() -- Here we don't care about received - if (not hn) and task_ip and task_ip:is_valid() then - task:get_resolver():resolve_ptr({ task = task, - name = task_ip:to_string(), - callback = recv_dns_cb, - forced = true - }) + if not hn then + if nreceived <= 1 then + task:insert_result(symbol, 1) + -- Avoid strict symbol inserting as the remaining symbols have already + -- quote a significant weight, so a message could be rejected by just + -- this property. + --task:insert_result(symbol_strict, 1) + -- Check for MUAs + local ua = task:get_header('User-Agent') + local xm = task:get_header('X-Mailer') + if (ua or xm) then + task:insert_result(symbol_mx, 1, (ua or xm)) + end + end return + else + if good_hosts then + for _, gh in ipairs(good_hosts) do + if string.find(hn, gh) then + return + end + end + end + + if nreceived <= 1 then + task:insert_result(symbol, 1) + for _, h in ipairs(bad_hosts) do + if string.find(hn, h) then + task:insert_result(symbol_strict, 1, h) + break + end + end + end end if nreceived <= 1 then @@ -181,10 +156,6 @@ if opts then for n, v in pairs(opts) do if n == 'symbol_strict' then symbol_strict = v - elseif n == 'symbol_rdns' then - symbol_rdns = v - elseif n == 'symbol_rdns_dnsfail' then - symbol_rdns_dnsfail = v elseif n == 'bad_host' then if type(v) == 'string' then bad_hosts[1] = v @@ -207,16 +178,6 @@ if opts then end rspamd_config:register_symbol({ - name = symbol_rdns, - type = 'virtual', - parent = id - }) - rspamd_config:register_symbol({ - name = symbol_rdns_dnsfail, - type = 'virtual', - parent = id - }) - rspamd_config:register_symbol({ name = symbol_strict, type = 'virtual', parent = id diff --git a/src/plugins/lua/spf.lua b/src/plugins/lua/spf.lua index 48f3c17be..356507250 100644 --- a/src/plugins/lua/spf.lua +++ b/src/plugins/lua/spf.lua @@ -56,6 +56,7 @@ local symbols = { dnsfail = "R_SPF_DNSFAIL", permfail = "R_SPF_PERMFAIL", na = "R_SPF_NA", + plusall = "R_SPF_PLUSALL", } local default_config = { @@ -118,6 +119,8 @@ local function spf_check_callback(task) local function flag_to_symbol(fl) if bit.band(fl, rspamd_spf.flags.temp_fail) ~= 0 then return local_config.symbols.dnsfail + elseif bit.band(fl, rspamd_spf.flags.plusall) ~= 0 then + return local_config.symbols.plusall elseif bit.band(fl, rspamd_spf.flags.perm_fail) ~= 0 then return local_config.symbols.permfail elseif bit.band(fl, rspamd_spf.flags.na) ~= 0 then diff --git a/src/rspamadm/configdump.c b/src/rspamadm/configdump.c index 167b4c891..456875cf2 100644 --- a/src/rspamadm/configdump.c +++ b/src/rspamadm/configdump.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 Vsevolod Stakhov + * Copyright 2024 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -445,6 +445,9 @@ rspamadm_configdump(int argc, char **argv, const struct rspamadm_command *cmd) ucl_object_fromdouble(gr->max_score), "max_score", strlen("max_score"), false); ucl_object_insert_key(gr_ucl, + ucl_object_fromdouble(gr->min_score), + "min_score", strlen("min_score"), false); + ucl_object_insert_key(gr_ucl, ucl_object_fromstring(gr->description), "description", strlen("description"), false); diff --git a/src/rspamadm/signtool.c b/src/rspamadm/signtool.c index 612a67c83..ddc3d45df 100644 --- a/src/rspamadm/signtool.c +++ b/src/rspamadm/signtool.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2024 Vsevolod Stakhov * * 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 + * 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, @@ -27,7 +27,6 @@ #include <sys/wait.h> #endif -static gboolean openssl = FALSE; static gboolean verify = FALSE; static gboolean quiet = FALSE; static char *suffix = NULL; @@ -37,7 +36,6 @@ static char *pubout = NULL; static char *keypair_file = NULL; static char *editor = NULL; static gboolean edit = FALSE; -enum rspamd_cryptobox_mode mode = RSPAMD_CRYPTOBOX_MODE_25519; static void rspamadm_signtool(int argc, char **argv, const struct rspamadm_command *cmd); @@ -53,8 +51,6 @@ struct rspamadm_command signtool_command = { }; static GOptionEntry entries[] = { - {"openssl", 'o', 0, G_OPTION_ARG_NONE, &openssl, - "Generate openssl nistp256 keypair not curve25519 one", NULL}, {"verify", 'v', 0, G_OPTION_ARG_NONE, &verify, "Verify signatures and not sign", NULL}, {"suffix", 'S', 0, G_OPTION_ARG_STRING, &suffix, @@ -327,11 +323,8 @@ rspamadm_sign_file(const char *fname, struct rspamd_cryptobox_keypair *kp) exit(EXIT_FAILURE); } - g_assert(rspamd_cryptobox_MAX_SIGBYTES >= - rspamd_cryptobox_signature_bytes(mode)); - sk = rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL); - rspamd_cryptobox_sign(sig, NULL, map, st.st_size, sk, mode); + rspamd_cryptobox_sign(sig, NULL, map, st.st_size, sk); if (edit) { /* We also need to rename .new file */ @@ -348,7 +341,7 @@ rspamadm_sign_file(const char *fname, struct rspamd_cryptobox_keypair *kp) rspamd_snprintf(sigpath, sizeof(sigpath), "%s%s", fname, suffix); - if (write(fd_sig, sig, rspamd_cryptobox_signature_bytes(mode)) == -1) { + if (write(fd_sig, sig, crypto_sign_bytes()) == -1) { rspamd_fprintf(stderr, "cannot write signature to %s: %s\n", sigpath, strerror(errno)); exit(EXIT_FAILURE); @@ -400,9 +393,6 @@ rspamadm_verify_file(const char *fname, const unsigned char *pk) struct stat st, st_sig; bool ret; - g_assert(rspamd_cryptobox_MAX_SIGBYTES >= - rspamd_cryptobox_signature_bytes(mode)); - if (suffix == NULL) { suffix = ".sig"; } @@ -439,7 +429,7 @@ rspamadm_verify_file(const char *fname, const unsigned char *pk) g_assert(fstat(fd_sig, &st_sig) != -1); - if (st_sig.st_size != rspamd_cryptobox_signature_bytes(mode)) { + if (st_sig.st_size != crypto_sign_bytes()) { close(fd_sig); rspamd_fprintf(stderr, "invalid signature size %s: %ud\n", fname, (unsigned int) st_sig.st_size); @@ -458,7 +448,7 @@ rspamadm_verify_file(const char *fname, const unsigned char *pk) } ret = rspamd_cryptobox_verify(map_sig, st_sig.st_size, - map, st.st_size, pk, mode); + map, st.st_size, pk); munmap(map, st.st_size); munmap(map_sig, st_sig.st_size); @@ -503,10 +493,6 @@ rspamadm_signtool(int argc, char **argv, const struct rspamadm_command *cmd) g_option_context_free(context); - if (openssl) { - mode = RSPAMD_CRYPTOBOX_MODE_NIST; - } - if (verify && (!pubkey && !pubkey_file)) { rspamd_fprintf(stderr, "no pubkey for verification\n"); exit(EXIT_FAILURE); @@ -549,14 +535,13 @@ rspamadm_signtool(int argc, char **argv, const struct rspamadm_command *cmd) flen--; } - pk = rspamd_pubkey_from_base32(map, flen, - RSPAMD_KEYPAIR_SIGN, mode); + pk = rspamd_pubkey_from_base32(map, flen, RSPAMD_KEYPAIR_SIGN); if (pk == NULL) { rspamd_fprintf(stderr, "bad size %s: %ud, %ud expected\n", pubkey_file, (unsigned int) flen, - rspamd_cryptobox_pk_sig_bytes(mode)); + crypto_sign_publickeybytes()); exit(EXIT_FAILURE); } @@ -564,13 +549,13 @@ rspamadm_signtool(int argc, char **argv, const struct rspamadm_command *cmd) } else { pk = rspamd_pubkey_from_base32(pubkey, strlen(pubkey), - RSPAMD_KEYPAIR_SIGN, mode); + RSPAMD_KEYPAIR_SIGN); if (pk == NULL) { rspamd_fprintf(stderr, "bad size %s: %ud, %ud expected\n", pubkey_file, (unsigned int) strlen(pubkey), - rspamd_cryptobox_pk_sig_bytes(mode)); + crypto_sign_publickeybytes()); exit(EXIT_FAILURE); } } diff --git a/src/rspamd_proxy.c b/src/rspamd_proxy.c index 4f08e81b9..dbdd2e5a7 100644 --- a/src/rspamd_proxy.c +++ b/src/rspamd_proxy.c @@ -395,7 +395,7 @@ rspamd_proxy_parse_upstream(rspamd_mempool_t *pool, elt = ucl_object_lookup(obj, "key"); if (elt != NULL) { up->key = rspamd_pubkey_from_base32(ucl_object_tostring(elt), 0, - RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); + RSPAMD_KEYPAIR_KEX); if (up->key == NULL) { g_set_error(err, rspamd_proxy_quark(), 100, @@ -571,7 +571,7 @@ rspamd_proxy_parse_mirror(rspamd_mempool_t *pool, elt = ucl_object_lookup(obj, "key"); if (elt != NULL) { up->key = rspamd_pubkey_from_base32(ucl_object_tostring(elt), 0, - RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); + RSPAMD_KEYPAIR_KEX); if (up->key == NULL) { g_set_error(err, rspamd_proxy_quark(), 100, @@ -1398,7 +1398,8 @@ proxy_backend_mirror_finish_handler(struct rspamd_http_connection *conn, bk_conn->err = "cannot parse ucl"; } - msg_info_session("finished mirror connection to %s", bk_conn->name); + msg_info_session("finished mirror connection to %s; HTTP code: %d", + bk_conn->name, msg->code); rspamd_upstream_ok(bk_conn->up); proxy_backend_close_connection(bk_conn); @@ -2203,6 +2204,8 @@ proxy_client_finish_handler(struct rspamd_http_connection *conn, rspamd_http_message_remove_header(msg, "Keep-Alive"); rspamd_http_message_remove_header(msg, "Connection"); rspamd_http_message_remove_header(msg, "Key"); + rspamd_http_message_add_header_len(msg, LOG_TAG_HEADER, session->pool->tag.uid, + sizeof(session->pool->tag.uid)); proxy_open_mirror_connections(session); rspamd_http_connection_reset(session->client_conn); @@ -2210,7 +2213,10 @@ proxy_client_finish_handler(struct rspamd_http_connection *conn, proxy_send_master_message(session); } else { - msg_info_session("finished master connection"); + msg_info_session("finished master connection to %s; HTTP code: %d", + rspamd_inet_address_to_string_pretty( + rspamd_upstream_addr_cur(session->master_conn->up)), + msg->code); proxy_backend_close_connection(session->master_conn); REF_RELEASE(session); } |