#include "dns.h"
#include "utlist.h"
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+
+/* special DNS tokens */
+#define DKIM_DNSKEYNAME "_domainkey"
+/* reserved DNS sub-zone */
+#define DKIM_DNSPOLICYNAME "_adsp" /* reserved DNS sub-zone */
+
+/* Canonization methods */
+#define DKIM_CANON_UNKNOWN (-1) /* unknown method */
+#define DKIM_CANON_SIMPLE 0 /* as specified in DKIM spec */
+#define DKIM_CANON_RELAXED 1 /* as specified in DKIM spec */
+
+#define DKIM_CANON_DEFAULT DKIM_CANON_SIMPLE
+
+/* Params */
+#define DKIM_PARAM_UNKNOWN (-1) /* unknown */
+#define DKIM_PARAM_SIGNATURE 0 /* b */
+#define DKIM_PARAM_SIGNALG 1 /* a */
+#define DKIM_PARAM_DOMAIN 2 /* d */
+#define DKIM_PARAM_CANONALG 3 /* c */
+#define DKIM_PARAM_QUERYMETHOD 4 /* q */
+#define DKIM_PARAM_SELECTOR 5 /* s */
+#define DKIM_PARAM_HDRLIST 6 /* h */
+#define DKIM_PARAM_VERSION 7 /* v */
+#define DKIM_PARAM_IDENTITY 8 /* i */
+#define DKIM_PARAM_TIMESTAMP 9 /* t */
+#define DKIM_PARAM_EXPIRATION 10 /* x */
+#define DKIM_PARAM_COPIEDHDRS 11 /* z */
+#define DKIM_PARAM_BODYHASH 12 /* bh */
+#define DKIM_PARAM_BODYLENGTH 13 /* l */
+
+/* Signature methods */
+#define DKIM_SIGN_UNKNOWN (-2) /* unknown method */
+#define DKIM_SIGN_DEFAULT (-1) /* use internal default */
+#define DKIM_SIGN_RSASHA1 0 /* an RSA-signed SHA1 digest */
+#define DKIM_SIGN_RSASHA256 1 /* an RSA-signed SHA256 digest */
+
#define msg_err_dkim(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
"dkim", ctx->pool->tag.uid, \
G_STRFUNC, \
[DKIM_PARAM_BODYLENGTH] = rspamd_dkim_parse_bodylength
};
+struct rspamd_dkim_context_s {
+ rspamd_mempool_t *pool;
+ gint sig_alg;
+ gint header_canon_type;
+ gint body_canon_type;
+ guint bhlen;
+ guint blen;
+ gsize len;
+ guint ver;
+ time_t timestamp;
+ time_t expiration;
+ gchar *domain;
+ gchar *selector;
+ gint8 *b;
+ gint8 *bh;
+
+ GPtrArray *hlist;
+ gchar *dns_key;
+ const gchar *dkim_header;
+
+ EVP_MD_CTX headers_hash;
+ EVP_MD_CTX body_hash;
+};
+
+struct rspamd_dkim_key_s {
+ guint8 *keydata;
+ guint keylen;
+ gsize decoded_len;
+ guint ttl;
+ RSA *key_rsa;
+ BIO *key_bio;
+ EVP_PKEY *key_evp;
+ ref_entry_t ref;
+};
+
+
struct rspamd_dkim_header {
gchar *name;
guint count;
const gchar *p, *c, *tag = NULL, *end;
gsize taglen;
gint param = DKIM_PARAM_UNKNOWN;
+ const EVP_MD *md_alg;
time_t now;
rspamd_dkim_context_t *ctx;
enum {
}
if (ctx->sig_alg == DKIM_SIGN_RSASHA1) {
/* Check bh length */
- if (ctx->bhlen != (guint)g_checksum_type_get_length (G_CHECKSUM_SHA1)) {
+ if (ctx->bhlen != (guint)EVP_MD_size (EVP_sha1 ())) {
g_set_error (err,
DKIM_ERROR,
DKIM_SIGERROR_BADSIG,
- "signature has incorrect length: %ud",
+ "signature has incorrect length: %u",
ctx->bhlen);
return NULL;
}
}
else if (ctx->sig_alg == DKIM_SIGN_RSASHA256) {
if (ctx->bhlen !=
- (guint)g_checksum_type_get_length (G_CHECKSUM_SHA256)) {
+ (guint)EVP_MD_size (EVP_sha256 ())) {
g_set_error (err,
DKIM_ERROR,
DKIM_SIGERROR_BADSIG,
- "signature has incorrect length: %ud",
+ "signature has incorrect length: %u",
ctx->bhlen);
return NULL;
}
/* Create checksums for further operations */
if (ctx->sig_alg == DKIM_SIGN_RSASHA1) {
- ctx->body_hash = g_checksum_new (G_CHECKSUM_SHA1);
- ctx->headers_hash = g_checksum_new (G_CHECKSUM_SHA1);
+ md_alg = EVP_sha1 ();
}
else if (ctx->sig_alg == DKIM_SIGN_RSASHA256) {
- ctx->body_hash = g_checksum_new (G_CHECKSUM_SHA256);
- ctx->headers_hash = g_checksum_new (G_CHECKSUM_SHA256);
+ md_alg = EVP_sha256 ();
}
else {
g_set_error (err,
DKIM_ERROR,
DKIM_SIGERROR_BADSIG,
"signature has unsupported signature algorithm");
+
return NULL;
}
- rspamd_mempool_add_destructor (ctx->pool,
- (rspamd_mempool_destruct_t)g_checksum_free,
- ctx->body_hash);
- rspamd_mempool_add_destructor (ctx->pool,
- (rspamd_mempool_destruct_t)g_checksum_free,
- ctx->headers_hash);
+ EVP_DigestInit (&ctx->body_hash, md_alg);
+ EVP_DigestInit (&ctx->headers_hash, md_alg);
ctx->dkim_header = sig;
#endif
REF_INIT_RETAIN (key, rspamd_dkim_key_free);
-#ifdef HAVE_OPENSSL
key->key_bio = BIO_new_mem_buf (key->keydata, key->decoded_len);
if (key->key_bio == NULL) {
g_set_error (err,
return NULL;
}
-#endif
return key;
}
void
rspamd_dkim_key_free (rspamd_dkim_key_t *key)
{
-#ifdef HAVE_OPENSSL
if (key->key_evp) {
EVP_PKEY_free (key->key_evp);
}
if (key->key_bio) {
BIO_free (key->key_bio);
}
-#endif
+
g_slice_free1 (key->keylen, key->keydata);
g_slice_free1 (sizeof (rspamd_dkim_key_t), key);
}
}
static gboolean
-rspamd_dkim_relaxed_body_step (rspamd_dkim_context_t *ctx, GChecksum *ck,
+rspamd_dkim_relaxed_body_step (rspamd_dkim_context_t *ctx, EVP_MD_CTX *ck,
const gchar **start, guint size,
guint *remain)
{
if (*remain > 0) {
size_t cklen = MIN(t - buf, *remain + added);
- g_checksum_update (ck, buf, cklen);
+ EVP_DigestUpdate (ck, buf, cklen);
*remain = *remain - (cklen - added);
#if 0
msg_debug_dkim ("update signature with buffer (%ud size, %ud remain, %ud added): %*s",
static gboolean
rspamd_dkim_simple_body_step (rspamd_dkim_context_t *ctx,
- GChecksum *ck, const gchar **start, guint size,
+ EVP_MD_CTX *ck, const gchar **start, guint size,
guint *remain)
{
const gchar *h;
if (*remain > 0) {
size_t cklen = MIN(t - buf, *remain + added);
- g_checksum_update (ck, buf, cklen);
+ EVP_DigestUpdate (ck, buf, cklen);
*remain = *remain - (cklen - added);
msg_debug_dkim ("update signature with body buffer "
"(%ud size, %ud remain, %ud added)",
if (start == NULL) {
/* Empty body */
if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
- g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 1);
+ EVP_DigestUpdate (&ctx->body_hash, CRLF, sizeof (CRLF) - 1);
}
else {
- g_checksum_update (ctx->body_hash, "", 0);
+ EVP_DigestUpdate (&ctx->body_hash, "", 0);
}
}
else {
if (end == start) {
/* Empty body */
if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
- g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 1);
+ EVP_DigestUpdate (&ctx->body_hash, CRLF, sizeof (CRLF) - 1);
}
else {
- g_checksum_update (ctx->body_hash, "", 0);
+ EVP_DigestUpdate (&ctx->body_hash, "", 0);
}
}
else {
if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
/* Simple canonization */
- while (rspamd_dkim_simple_body_step (ctx, ctx->body_hash,
+ while (rspamd_dkim_simple_body_step (ctx, &ctx->body_hash,
&start, end - start, &remain)) ;
}
else {
- while (rspamd_dkim_relaxed_body_step (ctx, ctx->body_hash,
+ while (rspamd_dkim_relaxed_body_step (ctx, &ctx->body_hash,
&start, end - start, &remain)) ;
}
}
/* Update hash converting all CR and LF to CRLF */
static void
-rspamd_dkim_hash_update (GChecksum *ck, const gchar *begin, gsize len)
+rspamd_dkim_hash_update (EVP_MD_CTX *ck, const gchar *begin, gsize len)
{
const gchar *p, *c, *end;
c = p;
while (p != end) {
if (*p == '\r') {
- g_checksum_update (ck, c, p - c);
- g_checksum_update (ck, CRLF, sizeof (CRLF) - 1);
+ EVP_DigestUpdate (ck, c, p - c);
+ EVP_DigestUpdate (ck, CRLF, sizeof (CRLF) - 1);
p++;
if (*p == '\n') {
p++;
c = p;
}
else if (*p == '\n') {
- g_checksum_update (ck, c, p - c);
- g_checksum_update (ck, CRLF, sizeof (CRLF) - 1);
+ EVP_DigestUpdate (ck, c, p - c);
+ EVP_DigestUpdate (ck, CRLF, sizeof (CRLF) - 1);
p++;
c = p;
}
}
}
if (p != c) {
- g_checksum_update (ck, c, p - c);
+ EVP_DigestUpdate (ck, c, p - c);
}
}
msg_debug_dkim ("initial update hash with signature part: %*s",
p - c + 2,
c);
- rspamd_dkim_hash_update (ctx->headers_hash, c, p - c + 2);
+ rspamd_dkim_hash_update (&ctx->headers_hash, c, p - c + 2);
skip = TRUE;
}
else if (skip && (*p == ';' || p == end - 1)) {
if (p - c + 1 > 0) {
msg_debug_dkim ("final update hash with signature part: %*s", p - c + 1, c);
- rspamd_dkim_hash_update (ctx->headers_hash, c, p - c + 1);
+ rspamd_dkim_hash_update (&ctx->headers_hash, c, p - c + 1);
}
}
if (!is_sign) {
msg_debug_dkim ("update signature with header: %s", buf);
- g_checksum_update (ctx->headers_hash, buf, t - buf);
+ EVP_DigestUpdate (&ctx->headers_hash, buf, t - buf);
}
else {
rspamd_dkim_signature_update (ctx, buf, t - buf);
msg_debug_dkim ("update signature with header: %*s",
elt->len,
elt->begin);
- rspamd_dkim_hash_update (ctx->headers_hash,
+ rspamd_dkim_hash_update (&ctx->headers_hash,
elt->begin,
elt->len);
}
msg_debug_dkim ("update signature with header: %*s",
elt->len + 1,
elt->begin);
- rspamd_dkim_hash_update (ctx->headers_hash,
+ rspamd_dkim_hash_update (&ctx->headers_hash,
elt->begin,
elt->len + 1);
}
{
const gchar *p, *headers_end = NULL, *end, *body_end;
gboolean got_cr = FALSE, got_crlf = FALSE, got_lf = FALSE;
- gchar *digest;
+ guchar raw_digest[EVP_MAX_MD_SIZE];
gsize dlen;
gint res = DKIM_CONTINUE;
guint i;
struct rspamd_dkim_header *dh;
-#ifdef HAVE_OPENSSL
gint nid;
-#endif
g_return_val_if_fail (ctx != NULL, DKIM_ERROR);
g_return_val_if_fail (key != NULL, DKIM_ERROR);
/* Canonize dkim signature */
rspamd_dkim_canonize_header (ctx, task, DKIM_SIGNHEADER, 1, TRUE);
- dlen = ctx->bhlen;
- digest = g_alloca (dlen);
- g_checksum_get_digest (ctx->body_hash, digest, &dlen);
+ dlen = EVP_MD_CTX_size (&ctx->body_hash);
+ EVP_DigestFinal (&ctx->body_hash, raw_digest, NULL);
/* Check bh field */
- if (memcmp (ctx->bh, digest, dlen) != 0) {
+ if (memcmp (ctx->bh, raw_digest, ctx->bhlen) != 0) {
msg_debug_dkim ("bh value missmatch: %*xs versus %*xs", dlen, ctx->bh,
- dlen, digest);
+ dlen, raw_digest);
return DKIM_REJECT;
}
- g_checksum_get_digest (ctx->headers_hash, digest, &dlen);
-#ifdef HAVE_OPENSSL
+ dlen = EVP_MD_CTX_size (&ctx->headers_hash);
+ EVP_DigestFinal (&ctx->headers_hash, raw_digest, NULL);
/* Check headers signature */
if (ctx->sig_alg == DKIM_SIGN_RSASHA1) {
nid = NID_sha1;
}
- if (RSA_verify (nid, digest, dlen, ctx->b, ctx->blen, key->key_rsa) != 1) {
+ if (RSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen, key->key_rsa) != 1) {
msg_debug_dkim ("rsa verify failed");
res = DKIM_REJECT;
}
-#endif
+
return res;
}
+
+rspamd_dkim_key_t *
+rspamd_dkim_key_ref (rspamd_dkim_key_t *k)
+{
+ REF_RETAIN (k);
+
+ return k;
+}
+
+void
+rspamd_dkim_key_unref (rspamd_dkim_key_t *k)
+{
+ REF_RELEASE (k);
+}
+
+const gchar*
+rspamd_dkim_get_domain (rspamd_dkim_context_t *ctx)
+{
+ if (ctx) {
+ return ctx->domain;
+ }
+
+ return NULL;
+}
+
+guint
+rspamd_dkim_key_get_ttl (rspamd_dkim_key_t *k)
+{
+ if (k) {
+ return k->ttl;
+ }
+
+ return 0;
+}
+
+const gchar*
+rspamd_dkim_get_dns_key (rspamd_dkim_context_t *ctx)
+{
+ if (ctx) {
+ return ctx->dns_key;
+ }
+
+ return NULL;
+}
#include "event.h"
#include "dns.h"
#include "ref.h"
-#ifdef HAVE_OPENSSL
-#include <openssl/rsa.h>
-#include <openssl/engine.h>
-#endif
/* Main types and definitions */
#define DKIM_SIGNHEADER "DKIM-Signature"
/* DKIM signature header */
-/* special DNS tokens */
-#define DKIM_DNSKEYNAME "_domainkey"
-/* reserved DNS sub-zone */
-#define DKIM_DNSPOLICYNAME "_adsp" /* reserved DNS sub-zone */
-
-/* Canonization methods */
-#define DKIM_CANON_UNKNOWN (-1) /* unknown method */
-#define DKIM_CANON_SIMPLE 0 /* as specified in DKIM spec */
-#define DKIM_CANON_RELAXED 1 /* as specified in DKIM spec */
-
-#define DKIM_CANON_DEFAULT DKIM_CANON_SIMPLE
-
-/* Signature methods */
-#define DKIM_SIGN_UNKNOWN (-2) /* unknown method */
-#define DKIM_SIGN_DEFAULT (-1) /* use internal default */
-#define DKIM_SIGN_RSASHA1 0 /* an RSA-signed SHA1 digest */
-#define DKIM_SIGN_RSASHA256 1 /* an RSA-signed SHA256 digest */
-
-/* Params */
-#define DKIM_PARAM_UNKNOWN (-1) /* unknown */
-#define DKIM_PARAM_SIGNATURE 0 /* b */
-#define DKIM_PARAM_SIGNALG 1 /* a */
-#define DKIM_PARAM_DOMAIN 2 /* d */
-#define DKIM_PARAM_CANONALG 3 /* c */
-#define DKIM_PARAM_QUERYMETHOD 4 /* q */
-#define DKIM_PARAM_SELECTOR 5 /* s */
-#define DKIM_PARAM_HDRLIST 6 /* h */
-#define DKIM_PARAM_VERSION 7 /* v */
-#define DKIM_PARAM_IDENTITY 8 /* i */
-#define DKIM_PARAM_TIMESTAMP 9 /* t */
-#define DKIM_PARAM_EXPIRATION 10 /* x */
-#define DKIM_PARAM_COPIEDHDRS 11 /* z */
-#define DKIM_PARAM_BODYHASH 12 /* bh */
-#define DKIM_PARAM_BODYLENGTH 13 /* l */
/* Errors (from OpenDKIM) */
#define DKIM_NOTFOUND 3 /* requested record not found */
#define DKIM_RECORD_ERROR 4 /* error requesting record */
-typedef struct rspamd_dkim_context_s {
- rspamd_mempool_t *pool;
- gint sig_alg;
- gint header_canon_type;
- gint body_canon_type;
- gsize len;
- gchar *domain;
- gchar *selector;
- time_t timestamp;
- time_t expiration;
- gint8 *b;
- gint8 *bh;
- guint bhlen;
- guint blen;
- GPtrArray *hlist;
- guint ver;
- gchar *dns_key;
- const gchar *dkim_header;
- GChecksum *headers_hash;
- GChecksum *body_hash;
-} rspamd_dkim_context_t;
-
-typedef struct rspamd_dkim_key_s {
- guint8 *keydata;
- guint keylen;
- gsize decoded_len;
- guint ttl;
-#ifdef HAVE_OPENSSL
- RSA *key_rsa;
- BIO *key_bio;
- EVP_PKEY *key_evp;
-#endif
- ref_entry_t ref;
-} rspamd_dkim_key_t;
+struct rspamd_dkim_context_s;
+typedef struct rspamd_dkim_context_s rspamd_dkim_context_t;
+
+struct rspamd_dkim_key_s;
+typedef struct rspamd_dkim_key_s rspamd_dkim_key_t;
struct rspamd_task;
rspamd_dkim_key_t *key,
struct rspamd_task *task);
+rspamd_dkim_key_t * rspamd_dkim_key_ref (rspamd_dkim_key_t *k);
+void rspamd_dkim_key_unref (rspamd_dkim_key_t *k);
+const gchar* rspamd_dkim_get_domain (rspamd_dkim_context_t *ctx);
+const gchar* rspamd_dkim_get_dns_key (rspamd_dkim_context_t *ctx);
+guint rspamd_dkim_key_get_ttl (rspamd_dkim_key_t *k);
+
/**
* Free DKIM key
* @param key
{
rspamd_dkim_key_t *key = k;
- REF_RELEASE (key);
+ rspamd_dkim_key_unref (key);
}
gint
gboolean all_done = TRUE, got_allow = FALSE;
const gchar *strict_value;
struct dkim_check_result *first, *cur, *sel = NULL;
- struct rspamd_task *task = res->task;
first = res->first;
}
if (cur->key != NULL && cur->res == -1) {
- msg_debug_task ("check dkim signature for %s domain from %s",
- cur->ctx->domain,
- cur->ctx->dns_key);
cur->res = rspamd_dkim_check (cur->ctx, cur->key, cur->task);
if (dkim_module_ctx->dkim_domains != NULL) {
/* Perform strict check */
if ((strict_value =
g_hash_table_lookup (dkim_module_ctx->dkim_domains,
- cur->ctx->domain)) != NULL) {
+ rspamd_dkim_get_domain (cur->ctx))) != NULL) {
if (!dkim_module_parse_strict (strict_value, &cur->mult_allow,
&cur->mult_deny)) {
cur->mult_allow = dkim_module_ctx->strict_multiplier;
cur->mult_allow * 1.0,
g_list_prepend (NULL,
rspamd_mempool_strdup (cur->task->task_pool,
- cur->ctx->domain)));
+ rspamd_dkim_get_domain (cur->ctx))));
got_allow = TRUE;
sel = NULL;
}
sel->mult_deny * 1.0,
g_list_prepend (NULL,
rspamd_mempool_strdup (sel->task->task_pool,
- sel->ctx->domain)));
+ rspamd_dkim_get_domain (sel->ctx))));
}
else {
rspamd_task_insert_result (sel->task,
1.0,
g_list_prepend (NULL,
rspamd_mempool_strdup (sel->task->task_pool,
- sel->ctx->domain)));
+ rspamd_dkim_get_domain (sel->ctx))));
}
}
GError *err)
{
struct dkim_check_result *res = ud;
+ struct rspamd_task *task;
+
+ task = res->task;
if (key != NULL) {
/*
* lru hash owns this object now
*/
rspamd_lru_hash_insert (dkim_module_ctx->dkim_hash,
- g_strdup (ctx->dns_key),
- key, res->task->tv.tv_sec, key->ttl);
+ g_strdup (rspamd_dkim_get_dns_key (ctx)),
+ key, res->task->tv.tv_sec, rspamd_dkim_key_get_ttl (key));
/* Another ref belongs to the check context */
- res->key = key;
- REF_RETAIN (res->key);
+ res->key = rspamd_dkim_key_ref (key);
/* Release key when task is processed */
rspamd_mempool_add_destructor (res->task->task_pool,
dkim_module_key_dtor, res->key);
}
else {
/* Insert tempfail symbol */
- msg_info ("cannot get key for domain %s: %e", ctx->dns_key, err);
+ msg_info_task ("cannot get key for domain %s: %e",
+ rspamd_dkim_get_dns_key (ctx), err);
if (err != NULL) {
res->res = DKIM_TRYAGAIN;
if (dkim_module_ctx->trusted_only &&
(dkim_module_ctx->dkim_domains == NULL ||
g_hash_table_lookup (dkim_module_ctx->dkim_domains,
- ctx->domain) == NULL)) {
+ rspamd_dkim_get_domain (ctx)) == NULL)) {
msg_debug_task ("skip dkim check for %s domain",
- ctx->domain);
+ rspamd_dkim_get_domain (ctx));
hlist = g_list_next (hlist);
continue;
}
key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash,
- ctx->dns_key,
+ rspamd_dkim_get_dns_key (ctx),
task->tv.tv_sec);
+
if (key != NULL) {
- debug_task ("found key for %s in cache", ctx->dns_key);
- cur->key = key;
- REF_RETAIN (cur->key);
+ cur->key = rspamd_dkim_key_ref (key);
/* Release key when task is processed */
rspamd_mempool_add_destructor (task->task_pool,
dkim_module_key_dtor, cur->key);
}
else {
- debug_task ("request key for %s from DNS", ctx->dns_key);
rspamd_get_dkim_key (ctx,
task,
dkim_module_key_handler,