Browse Source

[Fix] Implement new automata to skip empty lines for dkim signing

Issue: #651
Reported by: @FelixSchwarz
tags/1.3.0
Vsevolod Stakhov 8 years ago
parent
commit
242063230f
1 changed files with 153 additions and 16 deletions
  1. 153
    16
      src/libserver/dkim.c

+ 153
- 16
src/libserver/dkim.c View 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,

Loading…
Cancel
Save