From c3cb6d0798e480a3f32340471ca4f87f002e7a9c Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 14 Aug 2012 18:54:43 +0400 Subject: [PATCH] Another fix for simple canonicalization for body. --- src/dkim.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 10 deletions(-) diff --git a/src/dkim.c b/src/dkim.c index d042f3f7a..bcdadafdb 100644 --- a/src/dkim.c +++ b/src/dkim.c @@ -866,6 +866,62 @@ rspamd_dkim_relaxed_body_step (GChecksum *ck, const gchar **start, guint remain) return !finished; } +static gboolean +rspamd_dkim_simple_body_step (GChecksum *ck, const gchar **start, guint remain) +{ + const gchar *h; + static gchar buf[BUFSIZ]; + gchar *t; + guint len, inlen; + gboolean finished = FALSE; + + if (remain > sizeof (buf)) { + len = sizeof (buf); + } + else { + len = remain; + finished = TRUE; + } + inlen = sizeof (buf) - 1; + h = *start; + t = &buf[0]; + + while (len && inlen) { + if (*h == '\r' || *h == '\n') { + /* Replace a single \n or \r with \r\n */ + if (*h == '\n' && *(h - 1) != '\r') { + *t ++ = '\r'; + inlen --; + } + else if (*h == '\r' && *(h + 1) != '\n') { + *t ++ = *h ++; + *t ++ = '\n'; + if (inlen > 1) { + inlen -= 2; + } + else { + /* It is safe as inlen = sizeof (buf) - 1 */ + inlen = 0; + } + len --; + continue; + } + } + *t++ = *h++; + inlen --; + len --; + } + + *start = h; + +#if 0 + msg_debug ("update signature with buffer: %*s", t - buf, buf); +#endif + g_checksum_update (ck, buf, t - buf); + + return !finished; +} + static gboolean rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx, const gchar *start, const gchar *end) { @@ -896,15 +952,10 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx, const gchar *start, const else { if (ctx->body_canon_type == DKIM_CANON_SIMPLE) { /* Simple canonization */ - g_checksum_update (ctx->body_hash, start, end - start + 1); + while (rspamd_dkim_simple_body_step (ctx->body_hash, &start, end - start + 1)); } else { while (rspamd_dkim_relaxed_body_step (ctx->body_hash, &start, end - start + 1)); - return TRUE; - } - if (*end != '\n' || *(end - 1) != '\r') { - msg_debug ("append CRLF"); - g_checksum_update (ctx->body_hash, CRLF, sizeof (CRLF) - 1); } } return TRUE; @@ -1032,6 +1083,7 @@ rspamd_dkim_canonize_header_relaxed (rspamd_dkim_context_t *ctx, const gchar *he struct rspamd_dkim_sign_chunk { const gchar *begin; gsize len; + gboolean append_crlf; }; static gboolean @@ -1087,7 +1139,15 @@ rspamd_dkim_canonize_header_simple (rspamd_dkim_context_t *ctx, const gchar *hea /* c contains the beginning of header */ if (*p == '\n' && (!g_ascii_isspace (p[1]) || p[1] == '\0')) { chunk.begin = c; - chunk.len = p - c + 1; + if (*(p - 1) == '\r') { + chunk.len = p - c + 1; + chunk.append_crlf = FALSE; + } + else { + /* Need append CRLF as linefeed is not proper */ + chunk.len = p - c; + chunk.append_crlf = TRUE; + } g_array_append_val (to_sign, chunk); c = p + 1; state = 0; @@ -1103,13 +1163,26 @@ rspamd_dkim_canonize_header_simple (rspamd_dkim_context_t *ctx, const gchar *hea for (i = to_sign->len - 1; i >= 0 && count > 0; i --, count --) { elt = &g_array_index (to_sign, struct rspamd_dkim_sign_chunk, i); - msg_debug ("update signature with header: %*s", elt->len, elt->begin); - g_checksum_update (ctx->headers_hash, elt->begin, elt->len); + + if (!chunk.append_crlf) { + msg_debug ("update signature with header: %*s", elt->len, elt->begin); + g_checksum_update (ctx->headers_hash, elt->begin, elt->len); + } + else { + msg_debug ("update signature with header: %*s", elt->len + 1, elt->begin); + g_checksum_update (ctx->headers_hash, elt->begin, elt->len); + g_checksum_update (ctx->headers_hash, CRLF, sizeof (CRLF) - 1); + } } } else { elt = &g_array_index (to_sign, struct rspamd_dkim_sign_chunk, 0); - rspamd_dkim_signature_update (ctx, elt->begin, elt->len); + if (elt->append_crlf) { + rspamd_dkim_signature_update (ctx, elt->begin, elt->len + 1); + } + else { + rspamd_dkim_signature_update (ctx, elt->begin, elt->len); + } } } -- 2.39.5