aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2017-09-14 19:11:33 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2017-09-15 09:17:50 +0100
commitb62c1a9f357bc17540bd85534c6deec61d85e9e2 (patch)
treede67709d7d2944558fa1417b19aff568868d19d1
parent0fd5ec7e1e0da863189389cdd4746a2e2cae7f26 (diff)
downloadrspamd-b62c1a9f357bc17540bd85534c6deec61d85e9e2.tar.gz
rspamd-b62c1a9f357bc17540bd85534c6deec61d85e9e2.zip
[Feature] Improve parsing of DKIM keys: parse algorithm
-rw-r--r--src/libserver/dkim.c115
1 files changed, 84 insertions, 31 deletions
diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c
index d98befc14..ecbddb89a 100644
--- a/src/libserver/dkim.c
+++ b/src/libserver/dkim.c
@@ -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;
}