aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2012-05-30 01:24:30 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2012-05-30 01:24:30 +0400
commit83ea316af2bb37e25a88011b3fe794e2a10214a9 (patch)
tree249b24b9c14c169362dffc24e3c4684f2f33fc88
parentda1b50cb159a91092a6e6b689e4ea34197ce72f2 (diff)
downloadrspamd-83ea316af2bb37e25a88011b3fe794e2a10214a9.tar.gz
rspamd-83ea316af2bb37e25a88011b3fe794e2a10214a9.zip
* Implement relaxed canonization.
-rw-r--r--src/dkim.c114
1 files changed, 101 insertions, 13 deletions
diff --git a/src/dkim.c b/src/dkim.c
index 87959e6f4..c74222d3e 100644
--- a/src/dkim.c
+++ b/src/dkim.c
@@ -23,6 +23,7 @@
#include "config.h"
#include "main.h"
+#include "message.h"
#include "dkim.h"
#include "dns.h"
@@ -743,24 +744,24 @@ rspamd_dkim_relaxed_body_step (GChecksum *ck, const gchar **start, guint remain)
len = remain;
finished = TRUE;
}
- len = MIN (sizeof (buf), remain);
inlen = len;
h = *start;
t = &buf[0];
got_sp = FALSE;
while (len && inlen) {
- if ((*h == '\r' || *h == '\n') && got_sp) {
+ if (*h == '\r' || *h == '\n') {
/* Ignore spaces at the end of line */
- got_sp = FALSE;
- t --;
- len --;
+ if (got_sp) {
+ got_sp = FALSE;
+ t --;
+ }
}
else if (g_ascii_isspace (*h)) {
if (got_sp) {
/* Ignore multiply spaces */
h ++;
- inlen --;
+ len --;
continue;
}
else {
@@ -779,7 +780,7 @@ rspamd_dkim_relaxed_body_step (GChecksum *ck, const gchar **start, guint remain)
g_checksum_update (ck, buf, t - buf);
- return finished;
+ return !finished;
}
static gboolean
@@ -787,7 +788,7 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx, const gchar *start, const
{
if (start == NULL) {
/* Empty body */
- g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 2);
+ g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 1);
}
else {
end --;
@@ -801,7 +802,7 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx, const gchar *start, const
}
if (end == start || end == start + 2) {
/* Empty body */
- g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 2);
+ g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 1);
}
else {
if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
@@ -811,6 +812,10 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx, const gchar *start, const
else {
while (rspamd_dkim_relaxed_body_step (ctx->body_hash, &start, end - start + 1));
}
+ if (*end != '\n' || *(end - 1) != '\r') {
+ msg_debug ("append CRLF");
+ g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 1);
+ }
}
return TRUE;
}
@@ -852,17 +857,86 @@ rspamd_dkim_signature_update (rspamd_dkim_context_t *ctx, const gchar *begin, gu
p ++;
}
+ p --;
/* Skip \r\n at the end */
- while ((*p == '\r' || *p == '\n') && p > c) {
+ while ((*p == '\r' || *p == '\n') && p >= c) {
p --;
}
if (p - c > 0) {
- msg_debug ("final update hash with signature part: %*s", p - c, c);
- g_checksum_update (ctx->headers_hash, c, p - c);
+ msg_debug ("final update hash with signature part: %*s", p - c + 1, c);
+ g_checksum_update (ctx->headers_hash, c, p - c + 1);
}
}
static gboolean
+rspamd_dkim_canonize_header_relaxed (rspamd_dkim_context_t *ctx, const gchar *header, const gchar *header_name, gboolean is_sign)
+{
+ const gchar *h;
+ gchar *t, *buf, *v;
+ guint inlen;
+ gboolean got_sp, allocated = FALSE;
+
+ inlen = strlen (header) + strlen (header_name) + sizeof (":" CRLF);
+ if (inlen > BUFSIZ) {
+ buf = g_malloc (inlen);
+ allocated = TRUE;
+ }
+ else {
+ /* Faster */
+ buf = g_alloca (inlen);
+ }
+
+ /* Name part */
+ t = buf;
+ h = header_name;
+ while (*h) {
+ *t ++ = g_ascii_tolower (*h++);
+ }
+ *t++ = ':';
+
+ /* Value part */
+ v = t;
+ h = header;
+ got_sp = FALSE;
+
+ while (*h) {
+ if (g_ascii_isspace (*h)) {
+ if (got_sp) {
+ h ++;
+ continue;
+ }
+ else {
+ got_sp = TRUE;
+ }
+ }
+ else {
+ got_sp = FALSE;
+ }
+ *t ++ = *h ++;
+ }
+ if (g_ascii_isspace (*(t - 1))) {
+ t --;
+ }
+ *t++ = '\r';
+ *t++ = '\n';
+ *t = '\0';
+
+ if (!is_sign) {
+ msg_debug ("update signature with header: %s", buf);
+ g_checksum_update (ctx->headers_hash, buf, t - buf);
+ }
+ else {
+ rspamd_dkim_signature_update (ctx, buf, t - buf);
+ }
+
+ if (allocated) {
+ g_free (buf);
+ }
+
+ return TRUE;
+}
+
+static gboolean
rspamd_dkim_canonize_header_simple (rspamd_dkim_context_t *ctx, const gchar *headers, const gchar *header_name, gboolean is_sign)
{
const gchar *p, *c;
@@ -914,7 +988,7 @@ rspamd_dkim_canonize_header_simple (rspamd_dkim_context_t *ctx, const gchar *hea
g_checksum_update (ctx->headers_hash, c, p - c + 1);
}
else {
- rspamd_dkim_signature_update (ctx, c, p - c);
+ rspamd_dkim_signature_update (ctx, c, p - c + 1);
}
c = p + 1;
state = 0;
@@ -931,9 +1005,23 @@ rspamd_dkim_canonize_header_simple (rspamd_dkim_context_t *ctx, const gchar *hea
static gboolean
rspamd_dkim_canonize_header (rspamd_dkim_context_t *ctx, struct worker_task *task, const gchar *header_name, gboolean is_sig)
{
+ struct raw_header *rh;
+
if (ctx->header_canon_type == DKIM_CANON_SIMPLE) {
return rspamd_dkim_canonize_header_simple (ctx, task->raw_headers_str, header_name, is_sig);
}
+ else {
+ rh = g_hash_table_lookup (task->raw_headers, header_name);
+ if (rh) {
+ while (rh) {
+ if (! rspamd_dkim_canonize_header_relaxed (ctx, rh->value, header_name, is_sig)) {
+ return FALSE;
+ }
+ rh = rh->next;
+ }
+ return TRUE;
+ }
+ }
/* TODO: Implement relaxed algorithm */
return FALSE;