]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Implement new automata to skip empty lines for dkim signing
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 6 Jun 2016 13:46:09 +0000 (15:46 +0200)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 6 Jun 2016 13:46:09 +0000 (15:46 +0200)
Issue: #651
Reported by: @FelixSchwarz

src/libserver/dkim.c

index 5052960f0f3ea3120a63cd605abe93873aff70e0..1f65733ba2a13637a892dee369b1b5f1ecd3f0ee 100644 (file)
@@ -1260,6 +1260,147 @@ rspamd_dkim_simple_body_step (rspamd_dkim_context_t *ctx,
        return (len != 0);
 }
 
+static const gchar *
+rspamd_dkim_skip_empty_lines (const gchar *start, const gchar *end,
+               guint type, gboolean *need_crlf)
+{
+       const gchar *p = end - 1, *t;
+       enum {
+               init = 0,
+               init_2,
+               got_cr,
+               got_lf,
+               got_crlf,
+               test_spaces,
+       } state = init;
+       guint skip = 0;
+
+       while (p >= start + 2) {
+               switch (state) {
+               case init:
+                       if (*p == '\r') {
+                               state = got_cr;
+                       }
+                       else if (*p == '\n') {
+                               state = got_lf;
+                       }
+                       else if (type == DKIM_CANON_RELAXED && *p == ' ') {
+                               skip = 0;
+                               state = test_spaces;
+                       }
+                       else {
+                               if (type == DKIM_CANON_SIMPLE) {
+                                       *need_crlf = TRUE;
+                               }
+
+                               goto end;
+                       }
+                       break;
+               case init_2:
+                       if (*p == '\r') {
+                               state = got_cr;
+                       }
+                       else if (*p == '\n') {
+                               state = got_lf;
+                       }
+                       else if (type == DKIM_CANON_RELAXED && *p == ' ') {
+                               skip = 0;
+                               state = test_spaces;
+                       }
+                       else {
+                               goto end;
+                       }
+                       break;
+               case got_cr:
+                       if (*(p - 1) == '\r') {
+                               p --;
+                               state = got_cr;
+                       }
+                       else if (*(p - 1) == '\n') {
+                               if ((*p - 2) == '\r') {
+                                       /* \r\n\r -> we know about one line */
+                                       p -= 1;
+                                       state = got_crlf;
+                               }
+                               else {
+                                       /* \n\r -> we know about one line */
+                                       p -= 1;
+                                       state = got_lf;
+                               }
+                       }
+                       else if (type == DKIM_CANON_RELAXED && *(p - 1) == ' ') {
+                               skip = 1;
+                               state = test_spaces;
+                       }
+                       else {
+                               goto end;
+                       }
+                       break;
+               case got_lf:
+                       if (*(p - 1) == '\r') {
+                               state = got_crlf;
+                       }
+                       else if (*(p - 1) == '\n') {
+                               /* We know about one line */
+                               p --;
+                               state = got_lf;
+                       }
+                       else if (type == DKIM_CANON_RELAXED && *(p - 1) == ' ') {
+                               skip = 1;
+                               state = test_spaces;
+                       }
+                       else {
+                               goto end;
+                       }
+                       break;
+               case got_crlf:
+                       if (p > start - 2) {
+                               if (*(p - 3) == '\r') {
+                                       p -= 2;
+                                       state = got_cr;
+                               }
+                               else if (*(p - 3) == '\n') {
+                                       p -= 2;
+                                       state = got_lf;
+                               }
+                               else if (type == DKIM_CANON_RELAXED && *(p - 3) == ' ') {
+                                       skip = 2;
+                                       state = test_spaces;
+                               }
+                               else {
+                                       goto end;
+                               }
+                       }
+                       else {
+                               goto end;
+                       }
+                       break;
+               case test_spaces:
+                       t = p - skip;
+
+                       while (t > start - 2 && *t == ' ') {
+                               t --;
+                       }
+
+                       if (*t == '\r') {
+                               p = t;
+                               state = got_cr;
+                       }
+                       else if (*t == '\n') {
+                               p = t;
+                               state = got_lf;
+                       }
+                       else {
+                               goto end;
+                       }
+                       break;
+               }
+       }
+
+end:
+       return p;
+}
+
 static gboolean
 rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx,
        const gchar *start,
@@ -1267,6 +1408,7 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx,
 {
        const gchar *p;
        guint remain = ctx->len ? ctx->len : (guint)(end - start);
+       gboolean need_crlf = FALSE;
 
        if (start == NULL) {
                /* Empty body */
@@ -1279,22 +1421,9 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx,
        }
        else {
                /* Strip extra ending CRLF */
-               p = end - 1;
-               while (p >= start + 2) {
-                       if (*p == '\n' && *(p - 1) == '\r' && *(p - 2) == '\n') {
-                               p -= 2;
-                       }
-                       else if (*p == '\n' && *(p - 1) == '\n') {
-                               p--;
-                       }
-                       else if (*p == '\r' && *(p - 1) == '\r') {
-                               p--;
-                       }
-                       else {
-                               break;
-                       }
-               }
+               p = rspamd_dkim_skip_empty_lines (start, end, ctx->body_canon_type, &need_crlf);
                end = p + 1;
+
                if (end == start) {
                        /* Empty body */
                        if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
@@ -1308,7 +1437,15 @@ rspamd_dkim_canonize_body (rspamd_dkim_context_t *ctx,
                        if (ctx->body_canon_type == DKIM_CANON_SIMPLE) {
                                /* Simple canonization */
                                while (rspamd_dkim_simple_body_step (ctx, ctx->body_hash,
-                                               &start, end - start, &remain)) ;
+                                               &start, end - start, &remain));
+
+                               if (need_crlf) {
+                                       start = "\r\n";
+                                       end = start + 2;
+                                       remain = 2;
+                                       rspamd_dkim_simple_body_step (ctx, ctx->body_hash,
+                                                       &start, end - start, &remain);
+                               }
                        }
                        else {
                                while (rspamd_dkim_relaxed_body_step (ctx, ctx->body_hash,