Browse Source

* Start dkim support implementation.

tags/0.5.0
Vsevolod Stakhov 12 years ago
parent
commit
3f333be9d5
3 changed files with 717 additions and 0 deletions
  1. 1
    0
      lib/CMakeLists.txt
  2. 536
    0
      src/dkim.c
  3. 180
    0
      src/dkim.h

+ 1
- 0
lib/CMakeLists.txt View File

@@ -43,6 +43,7 @@ SET(RSPAMDLIBSRC
../src/cfg_utils.c
../src/cfg_xml.c
../src/diff.c
../src/dkim.c
../src/dns.c
../src/events.c
../src/expressions.c

+ 536
- 0
src/dkim.c View File

@@ -0,0 +1,536 @@
/* Copyright (c) 2010-2011, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "main.h"
#include "dkim.h"

/* Parser of dkim params */
typedef gboolean (*dkim_parse_param_f) (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);

static gboolean rspamd_dkim_parse_signature (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_signalg (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_domain (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_canonalg (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_ignore (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_selector (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_hdrlist (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_version (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_timestamp (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_expiration (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_bodyhash (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);
static gboolean rspamd_dkim_parse_bodylength (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err);


static const dkim_parse_param_f parser_funcs[] = {
[DKIM_PARAM_SIGNATURE] = rspamd_dkim_parse_signature,
[DKIM_PARAM_SIGNALG] = rspamd_dkim_parse_signalg,
[DKIM_PARAM_DOMAIN] = rspamd_dkim_parse_domain,
[DKIM_PARAM_CANONALG] = rspamd_dkim_parse_canonalg,
[DKIM_PARAM_QUERYMETHOD] = rspamd_dkim_parse_ignore,
[DKIM_PARAM_SELECTOR] = rspamd_dkim_parse_selector,
[DKIM_PARAM_HDRLIST] = rspamd_dkim_parse_hdrlist,
[DKIM_PARAM_VERSION] = rspamd_dkim_parse_version,
[DKIM_PARAM_IDENTITY] = rspamd_dkim_parse_ignore,
[DKIM_PARAM_TIMESTAMP] = rspamd_dkim_parse_timestamp,
[DKIM_PARAM_EXPIRATION] = rspamd_dkim_parse_expiration,
[DKIM_PARAM_COPIEDHDRS] = rspamd_dkim_parse_ignore,
[DKIM_PARAM_BODYHASH] = rspamd_dkim_parse_bodyhash,
[DKIM_PARAM_BODYLENGTH] = rspamd_dkim_parse_bodylength
};

#define DKIM_ERROR dkim_error_quark ()
GQuark
dkim_error_quark (void)
{
return g_quark_from_static_string ("dkim-error-quark");
}

/* Parsers implementation */
static gboolean
rspamd_dkim_parse_signature (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
ctx->b = memory_pool_alloc (ctx->pool, len + 1);
rspamd_strlcpy (ctx->b, param, len + 1);
g_base64_decode_inplace (ctx->b, &len);
return TRUE;
}

static gboolean
rspamd_dkim_parse_signalg (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
if (len == 8) {
if (memcmp (param, "rsa-sha1", len) == 0) {
ctx->sig_alg = DKIM_SIGN_RSASHA1;
return TRUE;
}
}
else if (len == 10) {
if (memcmp (param, "rsa-sha256", len) == 0) {
ctx->sig_alg = DKIM_SIGN_RSASHA256;
return TRUE;
}
}

g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_INVALID_A, "invalid dkim sign algorithm");
return FALSE;
}

static gboolean
rspamd_dkim_parse_domain (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
ctx->domain = memory_pool_alloc (ctx->pool, len + 1);
rspamd_strlcpy (ctx->domain, param, len + 1);
return TRUE;
}

static gboolean
rspamd_dkim_parse_canonalg (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
const gchar *p, *slash = NULL, *end = param + len;
gsize sl = 0;

p = param;
while (p != end) {
if (*p == '/') {
slash = p;
break;
}
p ++;
sl ++;
}

if (slash == NULL) {
/* Only check header */
if (len == 6 && memcmp (param, "simple", len) == 0) {
ctx->header_canon_type = DKIM_CANON_SIMPLE;
return TRUE;
}
else if (len == 7 && memcmp (param, "relaxed", len) == 0) {
ctx->header_canon_type = DKIM_CANON_RELAXED;
return TRUE;
}
}
else {
/* First check header */
if (sl == 6 && memcmp (param, "simple", len) == 0) {
ctx->header_canon_type = DKIM_CANON_SIMPLE;
}
else if (sl == 7 && memcmp (param, "relaxed", len) == 0) {
ctx->header_canon_type = DKIM_CANON_RELAXED;
}
else {
goto err;
}
/* Check body */
len = len - sl - 1;
slash ++;
if (len == 6 && memcmp (slash, "simple", len) == 0) {
ctx->body_canon_type = DKIM_CANON_SIMPLE;
return TRUE;
}
else if (len == 7 && memcmp (slash, "relaxed", len) == 0) {
ctx->body_canon_type = DKIM_CANON_RELAXED;
return TRUE;
}
}

err:
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_INVALID_A, "invalid dkim sign algorithm");
return FALSE;
}

static gboolean
rspamd_dkim_parse_ignore (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
/* Just ignore unused params */
return TRUE;
}

static gboolean
rspamd_dkim_parse_selector (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
ctx->selector = memory_pool_alloc (ctx->pool, len + 1);
rspamd_strlcpy (ctx->selector, param, len + 1);
return TRUE;
}

static gboolean
rspamd_dkim_parse_hdrlist (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
const gchar *c, *p, *end = param + len;
gchar *h;
gboolean from_found = FALSE;

c = param;
p = param;
while (p <= end) {
if ((*p == ':' || p == end) && p - c > 0) {
/* Insert new header to the list */
if (p == end) {
h = memory_pool_alloc (ctx->pool, p - c + 1);
rspamd_strlcpy (h, c, p - c + 1);
}
else {
h = memory_pool_alloc (ctx->pool, p - c);
rspamd_strlcpy (h, c, p - c);
}
/* Check mandatory from */
if (!from_found && g_ascii_strcasecmp (h, "from") == 0) {
from_found = TRUE;
}
ctx->hlist = g_list_prepend (ctx->hlist, h);
c = p + 1;
p ++;
}
else {
p ++;
}
}

if (!ctx->hlist) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_INVALID_H, "invalid dkim header list");
return FALSE;
}
else {
if (!from_found) {
g_list_free (ctx->hlist);
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_INVALID_H, "invalid dkim header list, from header is missing");
return FALSE;
}
/* Reverse list */
ctx->hlist = g_list_reverse (ctx->hlist);
memory_pool_add_destructor (ctx->pool, (pool_destruct_func)g_list_free, ctx->hlist);
}

return TRUE;
}

static gboolean
rspamd_dkim_parse_version (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
if (len != 1 || *param != '1') {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_VERSION, "invalid dkim version");
return FALSE;
}

ctx->ver = 1;
return TRUE;
}

static gboolean
rspamd_dkim_parse_timestamp (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
gulong val;

if (!rspamd_strtoul (param, len, &val)) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "invalid dkim timestamp");
return FALSE;
}
ctx->timestamp = val;

return TRUE;
}

static gboolean
rspamd_dkim_parse_expiration (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
gulong val;

if (!rspamd_strtoul (param, len, &val)) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "invalid dkim expiration");
return FALSE;
}
ctx->expiration = val;

return TRUE;
}

static gboolean
rspamd_dkim_parse_bodyhash (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
ctx->bh = memory_pool_alloc (ctx->pool, len + 1);
rspamd_strlcpy (ctx->bh, param, len + 1);
g_base64_decode_inplace (ctx->bh, &len);
return TRUE;
}

static gboolean
rspamd_dkim_parse_bodylength (rspamd_dkim_context_t* ctx, const gchar *param, gsize len, GError **err)
{
gulong val;

if (!rspamd_strtoul (param, len, &val)) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_INVALID_L, "invalid dkim body length");
return FALSE;
}
ctx->len = val;

return TRUE;
}

/**
* 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 gchar *sig, memory_pool_t *pool, GError **err)
{
const gchar *p, *c, *tag;
gsize taglen;
gint param = DKIM_PARAM_UNKNOWN;
time_t now;
rspamd_dkim_context_t *new;
enum {
DKIM_STATE_TAG = 0,
DKIM_STATE_AFTER_TAG,
DKIM_STATE_VALUE,
DKIM_STATE_SKIP_SPACES = 99,
DKIM_STATE_ERROR = 100
} state, next_state;


new = memory_pool_alloc0 (pool, sizeof (rspamd_dkim_context_t));
new->pool = pool;
new->header_canon_type = DKIM_CANON_DEFAULT;
new->body_canon_type = DKIM_CANON_DEFAULT;
new->sig_alg = DKIM_SIGN_UNKNOWN;
/* A simple state machine of parsing tags */
state = DKIM_STATE_SKIP_SPACES;
next_state = DKIM_STATE_TAG;
taglen = 0;
while (*p) {
switch (state) {
case DKIM_STATE_TAG:
if (g_ascii_isspace (*p)) {
taglen = p - c;
while (*p && g_ascii_isspace (*p)) {
/* Skip spaces before '=' sign */
p ++;
}
if (*p != '=') {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "invalid dkim param");
state = DKIM_STATE_ERROR;
}
else {
state = DKIM_STATE_SKIP_SPACES;
next_state = DKIM_STATE_AFTER_TAG;
param = DKIM_PARAM_UNKNOWN;
p ++;
tag = c;
}
}
else if (*p == '=') {
state = DKIM_STATE_SKIP_SPACES;
next_state = DKIM_STATE_AFTER_TAG;
param = DKIM_PARAM_UNKNOWN;
p ++;
tag = c;
}
else {
p ++;
taglen ++;
}
break;
case DKIM_STATE_AFTER_TAG:
/* We got tag at tag and len at taglen */
switch (taglen) {
case 0:
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "zero length dkim param");
state = DKIM_STATE_ERROR;
break;
case 1:
/* Simple tags */
switch (*tag) {
case 'v':
param = DKIM_PARAM_VERSION;
break;
case 'a':
param = DKIM_PARAM_SIGNALG;
break;
case 'b':
param = DKIM_PARAM_SIGNATURE;
break;
case 'c':
param = DKIM_PARAM_CANONALG;
break;
case 'd':
param = DKIM_PARAM_DOMAIN;
break;
case 'h':
param = DKIM_PARAM_HDRLIST;
break;
case 'i':
param = DKIM_PARAM_IDENTITY;
break;
case 'l':
param = DKIM_PARAM_BODYLENGTH;
break;
case 'q':
param = DKIM_PARAM_QUERYMETHOD;
break;
case 's':
param = DKIM_PARAM_SELECTOR;
break;
case 't':
param = DKIM_PARAM_TIMESTAMP;
break;
case 'x':
param = DKIM_PARAM_EXPIRATION;
break;
case 'z':
param = DKIM_PARAM_COPIEDHDRS;
break;
default:
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "invalid dkim param: %c", *tag);
state = DKIM_STATE_ERROR;
break;
}
break;
case 2:
if (tag[0] == 'b' && tag[1] == 'h') {
param = DKIM_PARAM_BODYHASH;
}
else {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "invalid dkim param: %c%c", tag[0], tag[1]);
state = DKIM_STATE_ERROR;
}
break;
default:
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_UNKNOWN, "invalid dkim param lenght: %zd", taglen);
state = DKIM_STATE_ERROR;
break;
}
if (state != DKIM_STATE_ERROR) {
/* Skip spaces */
p ++;
state = DKIM_STATE_SKIP_SPACES;
next_state = DKIM_STATE_VALUE;
}
break;
case DKIM_STATE_VALUE:
if (*p == ';') {
if (param == DKIM_PARAM_UNKNOWN || !parser_funcs[param](new, c, p - c - 1, err)) {
state = DKIM_STATE_ERROR;
}
}
else {
p ++;
}
break;
case DKIM_STATE_SKIP_SPACES:
if (g_ascii_isspace (*p)) {
p ++;
}
else {
c = p;
state = next_state;
}
break;
case DKIM_STATE_ERROR:
if (err) {
msg_info ("dkim parse failed: %s", (*err)->message);
return NULL;
}
else {
msg_info ("dkim parse failed: unknown error");
return NULL;
}
break;
}
}

/* Now check validity of signature */
if (new->b == NULL) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_B, "b parameter missing");
return NULL;
}
if (new->bh == NULL) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_BH, "bh parameter missing");
return NULL;
}
if (new->domain == NULL) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_D, "domain parameter missing");
return NULL;
}
if (new->selector == NULL) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_S, "selector parameter missing");
return NULL;
}
if (new->ver == 0) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_V, "v parameter missing");
return NULL;
}
if (new->hlist == NULL) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_H, "h parameter missing");
return NULL;
}
if (new->sig_alg == DKIM_SIGN_UNKNOWN) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EMPTY_S, "s parameter missing");
return NULL;
}
/* Check expiration */
now = time (NULL);
if (new->timestamp && new->timestamp > now) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_FUTURE, "signature was made in future, ignoring");
return NULL;
}
if (new->expiration && new->expiration < now) {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_EXPIRED, "signature has expired");
return NULL;
}

return new;
}

/**
* 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
*/
rspamd_dkim_key_t*
rspamd_get_dkim_key (rspamd_dkim_context_t *ctx, struct rspamd_dns_resolver *resolver,
struct rspamd_async_session *s)
{
/* TODO: add this parser as well */
return NULL;
}

/**
* 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
*/
gint
rspamd_dkim_check (rspamd_dkim_context_t *ctx, rspamd_dkim_key_t *key, struct worker_task *task)
{
/* TODO: this check must be implemented */
return DKIM_CONTINUE;
}

+ 180
- 0
src/dkim.h View File

@@ -0,0 +1,180 @@
/* Copyright (c) 2010-2011, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


#ifndef DKIM_H_
#define DKIM_H_

#include "config.h"
#include "event.h"
#include "dns.h"

/* 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_SIGERROR_UNKNOWN (-1) /* unknown error */
#define DKIM_SIGERROR_OK 0 /* no error */
#define DKIM_SIGERROR_VERSION 1 /* unsupported version */
#define DKIM_SIGERROR_DOMAIN 2 /* invalid domain (d=/i=) */
#define DKIM_SIGERROR_EXPIRED 3 /* signature expired */
#define DKIM_SIGERROR_FUTURE 4 /* signature in the future */
#define DKIM_SIGERROR_TIMESTAMPS 5 /* x= < t= */
#define DKIM_SIGERROR_UNUSED 6 /* OBSOLETE */
#define DKIM_SIGERROR_INVALID_HC 7 /* c= invalid (header) */
#define DKIM_SIGERROR_INVALID_BC 8 /* c= invalid (body) */
#define DKIM_SIGERROR_MISSING_A 9 /* a= missing */
#define DKIM_SIGERROR_INVALID_A 10 /* a= invalid */
#define DKIM_SIGERROR_MISSING_H 11 /* h= missing */
#define DKIM_SIGERROR_INVALID_L 12 /* l= invalid */
#define DKIM_SIGERROR_INVALID_Q 13 /* q= invalid */
#define DKIM_SIGERROR_INVALID_QO 14 /* q= option invalid */
#define DKIM_SIGERROR_MISSING_D 15 /* d= missing */
#define DKIM_SIGERROR_EMPTY_D 16 /* d= empty */
#define DKIM_SIGERROR_MISSING_S 17 /* s= missing */
#define DKIM_SIGERROR_EMPTY_S 18 /* s= empty */
#define DKIM_SIGERROR_MISSING_B 19 /* b= missing */
#define DKIM_SIGERROR_EMPTY_B 20 /* b= empty */
#define DKIM_SIGERROR_CORRUPT_B 21 /* b= corrupt */
#define DKIM_SIGERROR_NOKEY 22 /* no key found in DNS */
#define DKIM_SIGERROR_DNSSYNTAX 23 /* DNS reply corrupt */
#define DKIM_SIGERROR_KEYFAIL 24 /* DNS query failed */
#define DKIM_SIGERROR_MISSING_BH 25 /* bh= missing */
#define DKIM_SIGERROR_EMPTY_BH 26 /* bh= empty */
#define DKIM_SIGERROR_CORRUPT_BH 27 /* bh= corrupt */
#define DKIM_SIGERROR_BADSIG 28 /* signature mismatch */
#define DKIM_SIGERROR_SUBDOMAIN 29 /* unauthorized subdomain */
#define DKIM_SIGERROR_MULTIREPLY 30 /* multiple records returned */
#define DKIM_SIGERROR_EMPTY_H 31 /* h= empty */
#define DKIM_SIGERROR_INVALID_H 32 /* h= missing req'd entries */
#define DKIM_SIGERROR_TOOLARGE_L 33 /* l= value exceeds body size */
#define DKIM_SIGERROR_MBSFAILED 34 /* "must be signed" failure */
#define DKIM_SIGERROR_KEYVERSION 35 /* unknown key version */
#define DKIM_SIGERROR_KEYUNKNOWNHASH 36 /* unknown key hash */
#define DKIM_SIGERROR_KEYHASHMISMATCH 37 /* sig-key hash mismatch */
#define DKIM_SIGERROR_NOTEMAILKEY 38 /* not an e-mail key */
#define DKIM_SIGERROR_UNUSED2 39 /* OBSOLETE */
#define DKIM_SIGERROR_KEYTYPEMISSING 40 /* key type missing */
#define DKIM_SIGERROR_KEYTYPEUNKNOWN 41 /* key type unknown */
#define DKIM_SIGERROR_KEYREVOKED 42 /* key revoked */
#define DKIM_SIGERROR_KEYDECODE 43 /* key couldn't be decoded */
#define DKIM_SIGERROR_MISSING_V 44 /* v= tag missing */
#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 */

typedef struct rspamd_dkim_context_s {
memory_pool_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;
gchar *b;
gchar *bh;
GList *hlist;
guint ver;
} rspamd_dkim_context_t;

typedef struct rspamd_dkim_key_s {
memory_pool_t *pool;
/* TODO: make this structure */
} rspamd_dkim_key_t;

struct worker_task;

/**
* 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 gchar *sig, memory_pool_t *pool, GError **err);

/**
* 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
*/
rspamd_dkim_key_t* rspamd_get_dkim_key (rspamd_dkim_context_t *ctx, struct rspamd_dns_resolver *resolver,
struct rspamd_async_session *s);

/**
* 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
*/
gint rspamd_dkim_check (rspamd_dkim_context_t *ctx, rspamd_dkim_key_t *key, struct worker_task *task);

#endif /* DKIM_H_ */

Loading…
Cancel
Save