]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Parse CV results from Arc-Seal
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 25 May 2017 13:05:12 +0000 (14:05 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 25 May 2017 13:05:12 +0000 (14:05 +0100)
src/libserver/dkim.c
src/libserver/dkim.h
src/plugins/dkim_check.c

index b7d3f8ea1abb29b9ea1f0a0766b7b03ade3b607c..6e72c58b2850d04b75393ad9d0b2aa74b9b5eb14 100644 (file)
 #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 */
-#define DKIM_PARAM_IDX          14  /* i */
+enum rspamd_dkim_param_type {
+       DKIM_PARAM_UNKNOWN = -1,
+       DKIM_PARAM_SIGNATURE = 0,
+       DKIM_PARAM_SIGNALG,
+       DKIM_PARAM_DOMAIN,
+       DKIM_PARAM_CANONALG,
+       DKIM_PARAM_QUERYMETHOD,
+       DKIM_PARAM_SELECTOR,
+       DKIM_PARAM_HDRLIST,
+       DKIM_PARAM_VERSION,
+       DKIM_PARAM_IDENTITY,
+       DKIM_PARAM_TIMESTAMP,
+       DKIM_PARAM_EXPIRATION,
+       DKIM_PARAM_COPIEDHDRS,
+       DKIM_PARAM_BODYHASH,
+       DKIM_PARAM_BODYLENGTH,
+       DKIM_PARAM_IDX,
+       DKIM_PARAM_CV
+};
 
 /* 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 */
+enum rspamd_sign_type {
+       DKIM_SIGN_UNKNOWN = -2,
+       DKIM_SIGN_RSASHA1 = 0,
+       DKIM_SIGN_RSASHA256
+};
+
 #define RSPAMD_DKIM_MAX_ARC_IDX 10
 
 #define msg_err_dkim(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
@@ -89,6 +94,14 @@ struct rspamd_dkim_common_ctx {
        guint idx;
 };
 
+enum rspamd_arc_seal_cv {
+       RSPAMD_ARC_UNKNOWN = 0,
+       RSPAMD_ARC_NONE,
+       RSPAMD_ARC_INVALID,
+       RSPAMD_ARC_FAIL,
+       RSPAMD_ARC_PASS
+};
+
 struct rspamd_dkim_context_s {
        struct rspamd_dkim_common_ctx common;
        rspamd_mempool_t *pool;
@@ -103,6 +116,7 @@ struct rspamd_dkim_context_s {
        gint8 *b;
        gint8 *bh;
        gchar *dns_key;
+       enum rspamd_arc_seal_cv cv;
        const gchar *dkim_header;
 };
 
@@ -195,6 +209,10 @@ static gboolean rspamd_dkim_parse_idx (rspamd_dkim_context_t * ctx,
                const gchar *param,
                gsize len,
                GError **err);
+static gboolean rspamd_dkim_parse_cv (rspamd_dkim_context_t * ctx,
+               const gchar *param,
+               gsize len,
+               GError **err);
 
 
 static const dkim_parse_param_f parser_funcs[] = {
@@ -213,6 +231,7 @@ static const dkim_parse_param_f parser_funcs[] = {
        [DKIM_PARAM_BODYHASH] = rspamd_dkim_parse_bodyhash,
        [DKIM_PARAM_BODYLENGTH] = rspamd_dkim_parse_bodylength,
        [DKIM_PARAM_IDX] = rspamd_dkim_parse_idx,
+       [DKIM_PARAM_CV] = rspamd_dkim_parse_cv,
 };
 
 #define DKIM_ERROR dkim_error_quark ()
@@ -575,6 +594,40 @@ rspamd_dkim_parse_idx (rspamd_dkim_context_t * ctx,
        return TRUE;
 }
 
+static gboolean
+rspamd_dkim_parse_cv (rspamd_dkim_context_t * ctx,
+               const gchar *param,
+               gsize len,
+               GError **err)
+{
+
+       /* Only check header */
+       if (len == 4 && memcmp (param, "fail", len) == 0) {
+               ctx->cv = RSPAMD_ARC_FAIL;
+               return TRUE;
+       }
+       else if (len == 4 && memcmp (param, "pass", len) == 0) {
+               ctx->cv = RSPAMD_ARC_PASS;
+               return TRUE;
+       }
+       else if (len == 4 && memcmp (param, "none", len) == 0) {
+               ctx->cv = RSPAMD_ARC_NONE;
+               return TRUE;
+       }
+       else if (len == 7 && memcmp (param, "invalid", len) == 0) {
+               ctx->cv = RSPAMD_ARC_INVALID;
+               return TRUE;
+       }
+
+       g_set_error (err,
+                       DKIM_ERROR,
+                       DKIM_SIGERROR_UNKNOWN,
+                       "invalid arc seal verification result");
+
+       return FALSE;
+}
+
+
 static void
 rspamd_dkim_add_arc_seal_headers (rspamd_mempool_t *pool,
                struct rspamd_dkim_common_ctx *ctx)
@@ -796,6 +849,19 @@ rspamd_create_dkim_context (const gchar *sig,
                                                param = DKIM_PARAM_BODYHASH;
                                        }
                                }
+                               else if (tag[0] == 'c' && tag[1] == 'v') {
+                                       if (type != RSPAMD_DKIM_ARC_SEAL) {
+                                               g_set_error (err,
+                                                               DKIM_ERROR,
+                                                               DKIM_SIGERROR_UNKNOWN,
+                                                               "cv tag is valid for ARC-Seal only");
+                                               state = DKIM_STATE_ERROR;
+                                               break;
+                                       }
+                                       else {
+                                               param = DKIM_PARAM_CV;
+                                       }
+                               }
                                else {
                                        g_set_error (err,
                                                DKIM_ERROR,
@@ -976,6 +1042,16 @@ rspamd_create_dkim_context (const gchar *sig,
                return NULL;
        }
 
+       if (ctx->common.type != RSPAMD_DKIM_ARC_SEAL) {
+               if (ctx->cv == RSPAMD_ARC_UNKNOWN) {
+                       g_set_error (err,
+                                       DKIM_ERROR,
+                                       DKIM_SIGERROR_UNKNOWN,
+                                       "cv parameter missing or invalid for ARC");
+                       return NULL;
+               }
+       }
+
        /* Now create dns key to request further */
        taglen = strlen (ctx->domain) + strlen (ctx->selector) +
                sizeof (DKIM_DNSKEYNAME) + 2;
@@ -1923,7 +1999,7 @@ rspamd_dkim_canonize_header (struct rspamd_dkim_common_ctx *ctx,
  * @param task task to check
  * @return
  */
-gint
+enum rspamd_dkim_check_result
 rspamd_dkim_check (rspamd_dkim_context_t *ctx,
        rspamd_dkim_key_t *key,
        struct rspamd_task *task)
@@ -1932,7 +2008,7 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
        guchar raw_digest[EVP_MAX_MD_SIZE];
        EVP_MD_CTX *cpy_ctx;
        gsize dlen;
-       gint res = DKIM_CONTINUE;
+       enum rspamd_dkim_check_result res = DKIM_CONTINUE;
        guint i;
        struct rspamd_dkim_header *dh;
        gint nid;
@@ -2062,6 +2138,21 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx,
                res = DKIM_REJECT;
        }
 
+       if (ctx->common.type == RSPAMD_DKIM_ARC_SEAL && res == DKIM_CONTINUE) {
+               switch (ctx->cv) {
+               case RSPAMD_ARC_INVALID:
+                       msg_info_dkim ("arc seal is invalid i=%d", ctx->common.idx);
+                       res = DKIM_PERM_ERROR;
+                       break;
+               case RSPAMD_ARC_FAIL:
+                       msg_info_dkim ("arc seal failed i=%d", ctx->common.idx);
+                       res = DKIM_REJECT;
+                       break;
+               default:
+                       break;
+               }
+       }
+
        return res;
 }
 
@@ -2348,12 +2439,10 @@ rspamd_create_dkim_sign_context (struct rspamd_task *task,
 }
 
 
-GString*
-rspamd_dkim_sign (struct rspamd_task *task,
-               const gchar *selector, const gchar *domain,
-               time_t expire, gsize len,
-               guint idx,
-               rspamd_dkim_sign_context_t *ctx)
+GString *
+rspamd_dkim_sign (struct rspamd_task *task, const gchar *selector,
+               const gchar *domain, time_t expire, gsize len, guint idx,
+               const gchar *arc_cv, rspamd_dkim_sign_context_t *ctx)
 {
        GString *hdr;
        struct rspamd_dkim_header *dh;
@@ -2407,8 +2496,9 @@ rspamd_dkim_sign (struct rspamd_task *task,
                                domain, selector);
        }
        else {
-               /* Shouldn't be called for arc seal */
-               rspamd_printf_gstring (hdr, "i=%d; a=rsa-sha256; c=%s/%s; d=%s; s=%s; ",
+               g_assert (arc_cv != NULL);
+               rspamd_printf_gstring (hdr, "i=%d; a=rsa-sha256; c=%s/%s; d=%s; s=%s; cv=%s; ",
+                               arc_cv,
                                idx,
                                domain, selector);
        }
index 0a7eec21c77fb0be0777af43519fb9e0be3b47ab..2a8b0e0b54896eecb900bde5c24ddab573cf4739 100644 (file)
 #define DKIM_SIGERROR_EMPTY_V       45  /* v= tag empty */
 
 /* Check results */
-#define DKIM_CONTINUE   0   /* continue */
-#define DKIM_REJECT 1   /* reject */
-#define DKIM_TRYAGAIN   2   /* try again later */
-#define DKIM_NOTFOUND   3   /* requested record not found */
-#define DKIM_RECORD_ERROR   4   /* error requesting record */
-#define DKIM_PERM_ERROR     5   /* permanent error */
+enum rspamd_dkim_check_result {
+       DKIM_CONTINUE = 0,
+       DKIM_REJECT,
+       DKIM_TRYAGAIN,
+       DKIM_NOTFOUND,
+       DKIM_RECORD_ERROR,
+       DKIM_PERM_ERROR,
+};
 
 #define DKIM_CANON_SIMPLE   0   /* as specified in DKIM spec */
 #define DKIM_CANON_RELAXED  1   /* as specified in DKIM spec */
@@ -189,15 +191,13 @@ gboolean rspamd_get_dkim_key (rspamd_dkim_context_t *ctx,
  * @param task task to check
  * @return
  */
-gint rspamd_dkim_check (rspamd_dkim_context_t *ctx,
+enum rspamd_dkim_check_result rspamd_dkim_check (rspamd_dkim_context_t *ctx,
        rspamd_dkim_key_t *key,
        struct rspamd_task *task);
 
-GString* rspamd_dkim_sign (struct rspamd_task *task,
-               const gchar *selector, const gchar *domain,
-               time_t expire, gsize len,
-               guint idx,
-               rspamd_dkim_sign_context_t *ctx);
+GString *rspamd_dkim_sign (struct rspamd_task *task, const gchar *selector,
+               const gchar *domain, time_t expire, gsize len, guint idx,
+               const gchar *arc_cv, rspamd_dkim_sign_context_t *ctx);
 
 rspamd_dkim_key_t * rspamd_dkim_key_ref (rspamd_dkim_key_t *k);
 void rspamd_dkim_key_unref (rspamd_dkim_key_t *k);
index e5c7759592d2cddf834737fc48fd81438514e73f..effced5e27ebaff23e3453d0ef997376d078a98f 100644 (file)
@@ -681,7 +681,7 @@ lua_dkim_sign_handler (lua_State *L)
                return 1;
        }
 
-       hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, 0, ctx);
+       hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, 0, NULL, ctx);
 
        if (hdr) {
 
@@ -1185,7 +1185,8 @@ dkim_sign_callback (struct rspamd_task *task, void *unused)
                                        return;
                                }
 
-                               hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, 0, ctx);
+                               hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, 0, NULL,
+                                               ctx);
 
                                if (hdr) {
                                        rspamd_mempool_set_variable (task->task_pool,