From d793446a7bcf4ec5ab8697f0598fd4e5b1ac5960 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 2 Nov 2021 21:24:36 +0000 Subject: [PATCH] [Fix] Allow spaces in DKIM key records Issue: #3955 --- src/libserver/dkim.c | 101 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 12 deletions(-) diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index f83c64931..06318c847 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -1503,10 +1503,13 @@ rspamd_dkim_parse_key (const gchar *txt, gsize *keylen, GError **err) const gchar *c, *p, *end, *key = NULL, *alg = "rsa"; enum { read_tag = 0, + read_tag_before_eqsign, read_eqsign, read_p_tag, read_k_tag, - } state = read_tag; + ignore_value, + skip_spaces, + } state = read_tag, next_state; gchar tag = '\0'; gsize klen = 0, alglen = 0; @@ -1519,23 +1522,52 @@ rspamd_dkim_parse_key (const gchar *txt, gsize *keylen, GError **err) case read_tag: if (*p == '=') { state = read_eqsign; - } else { + } + else if (g_ascii_isspace (*p)) { + state = skip_spaces; + + if (tag != '\0') { + /* We had tag letter */ + next_state = read_tag_before_eqsign; + } + else { + /* We had no tag letter, so we ignore empty tag */ + next_state = read_tag; + } + } + else { tag = *p; } p++; break; + case read_tag_before_eqsign: + /* Input: spaces before eqsign + * Output: either read a next tag (previous had no value), or read value + * p is moved forward + */ + if (*p == '=') { + state = read_eqsign; + } + else { + tag = *p; + state = read_tag; + } + p ++; + break; case read_eqsign: + /* Always switch to skip spaces state and do not advance p */ + state = skip_spaces; + if (tag == 'p') { - state = read_p_tag; - c = p; - } else if (tag == 'k') { - state = read_k_tag; - c = p; - } else { + next_state = read_p_tag; + } + else if (tag == 'k') { + next_state = read_k_tag; + } + else { /* Unknown tag, ignore */ - state = read_tag; + next_state = ignore_value; tag = '\0'; - p++; } break; case read_p_tag: @@ -1544,8 +1576,18 @@ rspamd_dkim_parse_key (const gchar *txt, gsize *keylen, GError **err) key = c; state = read_tag; tag = '\0'; + p++; + } + else if (g_ascii_isspace (*p)) { + klen = p - c; + key = c; + state = skip_spaces; + next_state = read_tag; + tag = '\0'; + } + else { + p ++; } - p++; break; case read_k_tag: if (*p == ';') { @@ -1553,8 +1595,43 @@ rspamd_dkim_parse_key (const gchar *txt, gsize *keylen, GError **err) alg = c; state = read_tag; tag = '\0'; + p++; + } + else if (g_ascii_isspace (*p)) { + alglen = p - c; + alg = c; + state = skip_spaces; + next_state = read_tag; + tag = '\0'; + } + else { + p ++; + } + break; + case ignore_value: + if (*p == ';') { + state = read_tag; + tag = '\0'; + p ++; + } + else if (g_ascii_isspace (*p)) { + state = skip_spaces; + next_state = read_tag; + tag = '\0'; + } + else { + p ++; + } + break; + case skip_spaces: + /* Skip spaces and switch to the next state if needed */ + if (g_ascii_isspace(*p)) { + p ++; + } + else { + c = p; + state = next_state; } - p++; break; default: break; -- 2.39.5