Browse Source

[Feature] Improve parsing of DKIM keys: parse algorithm

tags/1.7.0
Vsevolod Stakhov 6 years ago
parent
commit
b62c1a9f35
1 changed files with 84 additions and 31 deletions
  1. 84
    31
      src/libserver/dkim.c

+ 84
- 31
src/libserver/dkim.c View File

@@ -1297,58 +1297,111 @@ static rspamd_dkim_key_t *
rspamd_dkim_parse_key (rspamd_dkim_context_t *ctx, const gchar *txt,
gsize *keylen, GError **err)
{
const gchar *c, *p, *end;
gint state = 0;
gsize len;
const gchar *c, *p, *end, *key = NULL, *alg = "rsa";
enum {
read_tag = 0,
read_eqsign,
read_p_tag,
read_k_tag,
} state = read_tag;
gchar tag = '\0';
gsize klen = 0, alglen = 0;

c = txt;
p = txt;
end = txt + strlen (txt);

while (p <= end) {
while (p < end) {
switch (state) {
case 0:
if (p != end && p[0] == 'p' && p[1] == '=') {
/* We got something like public key */
c = p + 2;
p = c;
state = 1;
case read_tag:
if (*p == '=') {
state = read_eqsign;
} else {
tag = *p;
}
else {
/* Ignore everything */
p++;
break;
case read_eqsign:
if (tag == 'p') {
state = read_p_tag;
c = p;
} else if (tag == 'k') {
state = read_k_tag;
c = p;
} else {
/* Unknown tag, ignore */
state = read_tag;
tag = '\0';
p++;
}
break;
case 1:
/* State when we got p= and looking for some public key */
if ((*p == ';' || p == end) && p > c) {
len = p - c;

if (keylen) {
*keylen = len;
}

return rspamd_dkim_make_key (ctx, c, len,
RSPAMD_DKIM_KEY_RSA, err);
case read_p_tag:
if (*p == ';') {
klen = p - c;
key = c;
state = read_tag;
tag = '\0';
}
else {
p++;
p++;
break;
case read_k_tag:
if (*p == ';') {
alglen = p - c;
alg = c;
state = read_tag;
tag = '\0';
}
p++;
break;
default:
break;
}
}

if (p - c == 0) {
/* Leftover */
switch (state) {
case read_p_tag:
klen = p - c;
key = c;
break;
case read_k_tag:
alglen = p - c;
alg = c;
break;
default:
break;
}

if (klen == 0 || key == NULL) {
g_set_error (err,
DKIM_ERROR,
DKIM_SIGERROR_KEYREVOKED,
"key was revoked");
DKIM_ERROR,
DKIM_SIGERROR_KEYFAIL,
"key is missing");
}

if (alglen == 0 || alg == NULL) {
alg = "rsa"; /* Implicit */
}

if (alglen == 8 && rspamd_lc_cmp (alg, "ecdsa256", alglen) == 0) {
if (keylen) {
*keylen = klen;
}

return rspamd_dkim_make_key (ctx, c, klen,
RSPAMD_DKIM_KEY_ECDSA, err);
}
else {
g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL,
"key was not found");
/* We assume RSA default in all cases */
if (alglen != 3 || rspamd_lc_cmp (alg, "rsa", alglen) != 0) {
msg_info_dkim ("invalid key algorithm: %*s", (gint)alglen, alg);
}
return rspamd_dkim_make_key (ctx, c, klen,
RSPAMD_DKIM_KEY_RSA, err);
}

g_assert_not_reached ();

return NULL;
}


Loading…
Cancel
Save