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,
{
const gchar *p;
guint remain = ctx->len ? ctx->len : (guint)(end - start);
+ gboolean need_crlf = FALSE;
if (start == NULL) {
/* Empty body */
}
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) {
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,