aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libcryptobox/cryptobox.h514
-rw-r--r--src/libserver/dkim.c199
2 files changed, 397 insertions, 316 deletions
diff --git a/src/libcryptobox/cryptobox.h b/src/libcryptobox/cryptobox.h
index 8382c8f68..54ef48c9a 100644
--- a/src/libcryptobox/cryptobox.h
+++ b/src/libcryptobox/cryptobox.h
@@ -1,22 +1,23 @@
/*
- * 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
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+* 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
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
#ifndef CRYPTOBOX_H_
#define CRYPTOBOX_H_
#include "config.h"
+#include "openssl/evp.h"
#include <sodium.h>
@@ -25,13 +26,13 @@ extern "C" {
#endif
struct rspamd_cryptobox_segment {
- unsigned char *data;
- gsize len;
+ unsigned char *data;
+ gsize len;
};
#if defined(__GNUC__) && \
- ((defined(__clang__) && (__clang_major__ >= 4 || (__clang_major__ >= 3 && __clang_minor__ >= 8))) || \
- ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) || (__GNUC__ > 4)))
+ ((defined(__clang__) && (__clang_major__ >= 4 || (__clang_major__ >= 3 && __clang_minor__ >= 8))) || \
+ ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) || (__GNUC__ > 4)))
#define RSPAMD_HAS_TARGET_ATTR 1
#endif
@@ -68,366 +69,379 @@ 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
+ RSPAMD_CRYPTOBOX_MODE_25519 = 0,
+ RSPAMD_CRYPTOBOX_MODE_NIST
};
struct rspamd_cryptobox_library_ctx {
- char *cpu_extensions;
- const char *chacha20_impl;
- const char *base64_impl;
- unsigned long cpu_config;
+ char *cpu_extensions;
+ const char *chacha20_impl;
+ const char *base64_impl;
+ unsigned long cpu_config;
};
/**
- * 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
- */
+* 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);
+ enum rspamd_cryptobox_mode mode);
/**
- * Generate new keypair for signing
- * @param pk public key buffer
- * @param sk secret key buffer
- */
+* 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);
+ enum rspamd_cryptobox_mode mode);
/**
- * 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);
+
+/**
+* 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);
-/**
- * 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);
-
/**
- * 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);
-
-/**
- * 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,
+ const rspamd_pk_t pk, const rspamd_sk_t sk, const rspamd_mac_t sig,
enum rspamd_cryptobox_mode mode);
/**
- * 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);
+
+/**
+* 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);
+ gsize cnt,
+ const rspamd_nonce_t nonce,
+ const rspamd_nm_t nm, rspamd_mac_t sig,
+ enum rspamd_cryptobox_mode mode);
/**
- * 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_nonce_t nonce,
+ const rspamd_nm_t nm, const rspamd_mac_t sig,
+ 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
- */
+* 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);
+ const rspamd_sk_t sk, enum rspamd_cryptobox_mode mode);
/**
- * 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);
-
-/**
- * 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
- */
+ const unsigned char *m, gsize mlen,
+ const rspamd_sk_t sk,
+ enum rspamd_cryptobox_mode mode);
+
+void rspamd_cryptobox_sign_compat(int nid, unsigned char *sig, unsigned long long *siglen_p,
+ const unsigned char *m, gsize mlen,
+ struct evp_pkey_st *sec_key,
+ enum rspamd_cryptobox_mode mode);
+
+/**
+* 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);
-
-/**
- * Securely clear the buffer specified
- * @param buf buffer to zero
- * @param buflen length of buffer
- */
+ gsize siglen,
+ const unsigned char *m,
+ gsize mlen,
+ const rspamd_pk_t pk,
+ enum rspamd_cryptobox_mode mode);
+
+bool rspamd_cryptobox_verify_compat(int nid,
+ const unsigned char *sig,
+ gsize siglen,
+ const unsigned char *m,
+ gsize mlen,
+ struct evp_pkey_st *pub_key,
+ enum rspamd_cryptobox_mode mode);
+
+/**
+* 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);
+ unsigned long long inlen,
+ const rspamd_sipkey_t k);
enum rspamd_cryptobox_pbkdf_type {
- RSPAMD_CRYPTOBOX_PBKDF2 = 0,
- RSPAMD_CRYPTOBOX_CATENA
+ RSPAMD_CRYPTOBOX_PBKDF2 = 0,
+ RSPAMD_CRYPTOBOX_CATENA
};
/**
- * 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,
- unsigned int complexity,
- enum rspamd_cryptobox_pbkdf_type type);
+ const uint8_t *salt, gsize salt_len,
+ uint8_t *key, gsize key_len,
+ unsigned int complexity,
+ enum rspamd_cryptobox_pbkdf_type type);
/**
- * Real size of rspamd cryptobox public key
- */
+* 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
- */
+* 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
- */
+* Real size of crypto nonce
+*/
unsigned int rspamd_cryptobox_nonce_bytes(enum rspamd_cryptobox_mode mode);
/**
- * Real size of rspamd cryptobox secret key
- */
+* 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
- */
+* 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
- */
+* 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
- */
+* 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
- */
+* 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);
+ 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);
+ 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,
- const unsigned char *key,
- gsize keylen);
+ const unsigned char *data,
+ gsize len,
+ const unsigned char *key,
+ gsize keylen);
enum rspamd_cryptobox_fast_hash_type {
- RSPAMD_CRYPTOBOX_XXHASH64 = 0,
- RSPAMD_CRYPTOBOX_XXHASH32,
- RSPAMD_CRYPTOBOX_XXHASH3,
- RSPAMD_CRYPTOBOX_MUMHASH,
- RSPAMD_CRYPTOBOX_T1HA,
- RSPAMD_CRYPTOBOX_HASHFAST,
- RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT
+ RSPAMD_CRYPTOBOX_XXHASH64 = 0,
+ RSPAMD_CRYPTOBOX_XXHASH32,
+ RSPAMD_CRYPTOBOX_XXHASH3,
+ RSPAMD_CRYPTOBOX_MUMHASH,
+ RSPAMD_CRYPTOBOX_T1HA,
+ RSPAMD_CRYPTOBOX_HASHFAST,
+ RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT
};
/* Non crypto hash IUF interface */
typedef struct CRYPTO_ALIGN(64) rspamd_cryptobox_fast_hash_state_s {
- unsigned char opaque[576]; /* Required for xxhash3 */
- enum rspamd_cryptobox_fast_hash_type type;
+ unsigned char opaque[576]; /* Required for xxhash3 */
+ enum rspamd_cryptobox_fast_hash_type type;
} rspamd_cryptobox_fast_hash_state_t;
/**
- * 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);
+ 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);
+ 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);
+ 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);
+ 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
- */
+ 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
+*/
gboolean rspamd_cryptobox_base64_decode(const char *in, gsize inlen,
- unsigned char *out, gsize *outlen);
+ 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/libserver/dkim.c b/src/libserver/dkim.c
index 742e4db8b..3d974c0c4 100644
--- a/src/libserver/dkim.c
+++ b/src/libserver/dkim.c
@@ -1,18 +1,18 @@
/*
- * 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
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+* 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
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
#include "config.h"
#include "rspamd.h"
#include "message.h"
@@ -67,25 +67,25 @@ enum rspamd_dkim_param_type {
#define RSPAMD_DKIM_MAX_ARC_IDX 10
#define msg_err_dkim(...) rspamd_default_log_function(G_LOG_LEVEL_CRITICAL, \
+ "dkim", ctx->pool->tag.uid, \
+ RSPAMD_LOG_FUNC, \
+ __VA_ARGS__)
+#define msg_warn_dkim(...) rspamd_default_log_function(G_LOG_LEVEL_WARNING, \
"dkim", ctx->pool->tag.uid, \
RSPAMD_LOG_FUNC, \
__VA_ARGS__)
-#define msg_warn_dkim(...) rspamd_default_log_function(G_LOG_LEVEL_WARNING, \
- "dkim", ctx->pool->tag.uid, \
- RSPAMD_LOG_FUNC, \
- __VA_ARGS__)
#define msg_info_dkim(...) rspamd_default_log_function(G_LOG_LEVEL_INFO, \
- "dkim", ctx->pool->tag.uid, \
- RSPAMD_LOG_FUNC, \
- __VA_ARGS__)
+ "dkim", ctx->pool->tag.uid, \
+ RSPAMD_LOG_FUNC, \
+ __VA_ARGS__)
#define msg_debug_dkim(...) rspamd_conditional_debug_fast(NULL, NULL, \
- rspamd_dkim_log_id, "dkim", ctx->pool->tag.uid, \
- RSPAMD_LOG_FUNC, \
- __VA_ARGS__)
+ rspamd_dkim_log_id, "dkim", ctx->pool->tag.uid, \
+ RSPAMD_LOG_FUNC, \
+ __VA_ARGS__)
#define msg_debug_dkim_taskless(...) rspamd_conditional_debug_fast(NULL, NULL, \
- rspamd_dkim_log_id, "dkim", "", \
- RSPAMD_LOG_FUNC, \
- __VA_ARGS__)
+ rspamd_dkim_log_id, "dkim", "", \
+ RSPAMD_LOG_FUNC, \
+ __VA_ARGS__)
INIT_LOG_MODULE(dkim)
@@ -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);
}
@@ -1430,8 +1430,8 @@ rspamd_dkim_make_key(const char *keydata,
return NULL;
}
-
if (type == RSPAMD_DKIM_KEY_RSA) {
+#if OPENSSL_VERSION_MAJOR < 3
key->key.key_rsa = EVP_PKEY_get1_RSA(key->key_evp);
if (key->key.key_rsa == NULL) {
@@ -1443,8 +1443,10 @@ rspamd_dkim_make_key(const char *keydata,
return NULL;
}
+#endif
}
else {
+#if OPENSSL_VERSION_MAJOR < 3
key->key.key_ecdsa = EVP_PKEY_get1_EC_KEY(key->key_evp);
if (key->key.key_ecdsa == NULL) {
@@ -1456,7 +1458,9 @@ rspamd_dkim_make_key(const char *keydata,
return NULL;
}
+#endif
}
+
}
return key;
@@ -1473,15 +1477,16 @@ 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 OPENSSL_VERSION_MAJOR < 3
if (key->type == RSPAMD_DKIM_KEY_RSA) {
if (key->key.key_rsa) {
RSA_free(key->key.key_rsa);
@@ -1492,6 +1497,7 @@ void rspamd_dkim_key_free(rspamd_dkim_key_t *key)
EC_KEY_free(key->key.key_ecdsa);
}
}
+#endif
/* Nothing in case of eddsa key */
if (key->key_bio) {
BIO_free(key->key_bio);
@@ -1507,11 +1513,13 @@ void rspamd_dkim_sign_key_free(rspamd_dkim_sign_key_t *key)
if (key->key_evp) {
EVP_PKEY_free(key->key_evp);
}
+#if OPENSSL_VERSION_MAJOR < 3
if (key->type == RSPAMD_DKIM_KEY_RSA) {
if (key->key.key_rsa) {
RSA_free(key->key.key_rsa);
}
}
+#endif
if (key->key_bio) {
BIO_free(key->key_bio);
}
@@ -1570,9 +1578,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 +1767,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 +2195,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) {
@@ -2461,9 +2469,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 +2517,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 +2700,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,
@@ -2916,6 +2924,7 @@ rspamd_dkim_check(rspamd_dkim_context_t *ctx,
switch (key->type) {
case RSPAMD_DKIM_KEY_RSA:
+#if OPENSSL_VERSION_MAJOR < 3
if (RSA_verify(nid, raw_digest, dlen, ctx->b, ctx->blen,
key->key.key_rsa) != 1) {
msg_debug_dkim("headers rsa verify failed");
@@ -2933,8 +2942,28 @@ rspamd_dkim_check(rspamd_dkim_context_t *ctx,
RSPAMD_DKIM_KEY_ID_LEN, rspamd_dkim_key_id(key),
ctx->dkim_header);
}
+#else
+ if (rspamd_cryptobox_verify_compat(nid, ctx->b, ctx->blen, raw_digest, dlen,
+ key->key_evp, RSPAMD_CRYPTOBOX_MODE_NIST) != 1) {
+ msg_debug_dkim("headers rsa verify failed");
+ ERR_clear_error();
+ res->rcode = DKIM_REJECT;
+ res->fail_reason = "headers rsa verify failed";
+
+ msg_info_dkim(
+ "%s: headers RSA verification failure; "
+ "body length %d->%d; headers length %d; d=%s; s=%s; key_md5=%*xs; orig header: %s",
+ rspamd_dkim_type_to_string(ctx->common.type),
+ (int) (body_end - body_start), ctx->common.body_canonicalised,
+ ctx->common.headers_canonicalised,
+ ctx->domain, ctx->selector,
+ RSPAMD_DKIM_KEY_ID_LEN, rspamd_dkim_key_id(key),
+ ctx->dkim_header);
+ }
+#endif
break;
case RSPAMD_DKIM_KEY_ECDSA:
+#if OPENSSL_VERSION_MAJOR < 3
if (ECDSA_verify(nid, raw_digest, dlen, ctx->b, ctx->blen,
key->key.key_ecdsa) != 1) {
msg_info_dkim(
@@ -2951,7 +2980,26 @@ rspamd_dkim_check(rspamd_dkim_context_t *ctx,
res->rcode = DKIM_REJECT;
res->fail_reason = "headers ecdsa verify failed";
}
+#else
+ if (rspamd_cryptobox_verify_compat(nid, ctx->b, ctx->blen, raw_digest, dlen,
+ key->key_evp, RSPAMD_CRYPTOBOX_MODE_NIST) != 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",
+ rspamd_dkim_type_to_string(ctx->common.type),
+ (int) (body_end - body_start), ctx->common.body_canonicalised,
+ ctx->common.headers_canonicalised,
+ ctx->domain, ctx->selector,
+ RSPAMD_DKIM_KEY_ID_LEN, rspamd_dkim_key_id(key),
+ ctx->dkim_header);
+ msg_debug_dkim("headers ecdsa verify failed");
+ ERR_clear_error();
+ res->rcode = DKIM_REJECT;
+ res->fail_reason = "headers ecdsa verify failed";
+ }
+#endif
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)) {
@@ -3200,6 +3248,7 @@ rspamd_dkim_sign_key_load(const char *key, gsize len,
goto end;
}
}
+#if OPENSSL_VERSION_MAJOR < 3
nkey->key.key_rsa = EVP_PKEY_get1_RSA(nkey->key_evp);
if (nkey->key.key_rsa == NULL) {
g_set_error(err,
@@ -3212,6 +3261,7 @@ rspamd_dkim_sign_key_load(const char *key, gsize len,
goto end;
}
nkey->type = RSPAMD_DKIM_KEY_RSA;
+#endif
}
REF_INIT_RETAIN(nkey, rspamd_dkim_sign_key_free);
@@ -3536,7 +3586,9 @@ 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) {
+#if OPENSSL_VERSION_MAJOR < 3
sig_len = RSA_size(ctx->key->key.key_rsa);
sig_buf = g_alloca(sig_len);
@@ -3548,6 +3600,13 @@ rspamd_dkim_sign(struct rspamd_task *task, const char *selector,
return NULL;
}
+#else
+ sig_len = EVP_PKEY_get_size(ctx->key->key_evp);
+ sig_buf = g_alloca(sig_len);
+ rspamd_cryptobox_sign_compat(NID_sha256, sig_buf, NULL, raw_digest, dlen,
+ ctx->key->key_evp, RSPAMD_CRYPTOBOX_MODE_NIST);
+ msg_debug("signed RSA");
+#endif
}
else if (ctx->key->type == RSPAMD_DKIM_KEY_EDDSA) {
sig_len = rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519);
@@ -3601,11 +3660,19 @@ rspamd_dkim_match_keys(rspamd_dkim_key_t *pk,
return FALSE;
}
}
+#if OPENSSL_VERSION_MAJOR >= 3
+ else if (EVP_PKEY_eq(pk->key_evp, sk->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->key_evp, sk->key_evp) != 1) {
g_set_error(err, dkim_error_quark(), DKIM_SIGERROR_KEYHASHMISMATCH,
"pubkey does not match private key");
return FALSE;
}
+#endif
return TRUE;
}