aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-07-07 15:51:35 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-07-07 16:49:46 +0300
commitc0165798d33e476ea8d8dc7f854b0b5edbe7278b (patch)
tree4ee00e8b5bf3798fffff349cefe3e51fa337366f /src
parente112614a2abc999b4f63a5e8dc9349e8d07ace9d (diff)
downloadmailfromd-c0165798d33e476ea8d8dc7f854b0b5edbe7278b.tar.gz
mailfromd-c0165798d33e476ea8d8dc7f854b0b5edbe7278b.tar.bz2
Fixes in DKIM code
* lib/dns.c (dkim_lookup): The v= tag is optional. * src/builtin/dkim.bi (dkim_sign): Insert the created header at the beginning. (dkim_verify): Mark with MF_DSEXP. * src/dkim-canonicalize.c (dkim_canonicalizer): Fix relaxed body canonicalization: ignore whitespace at the end of the line (before CRLF). * src/dkim.c (dkim_str_to_canon_type): Take two arguments. Return the pointer to the first character after the spec in *endp. All uses changed. (dkim_signature_parse): Fix typo (missing else). Fix c= tag parsing. (dkim_sig_validate): The q= tag is optional. Fix verification of the i= tag. (pubkey_validate): Validate v= tag, if supplied. Fix validation of the key type and algorithm. * src/dkim.h (DKIM_KEYRECORD_VERSION): New constant.
Diffstat (limited to 'src')
-rw-r--r--src/builtin/dkim.bi12
-rw-r--r--src/dkim-canonicalize.c18
-rw-r--r--src/dkim.c66
-rw-r--r--src/dkim.h3
4 files changed, 68 insertions, 31 deletions
diff --git a/src/builtin/dkim.bi b/src/builtin/dkim.bi
index 52ac4e3c..a85c2b51 100644
--- a/src/builtin/dkim.bi
+++ b/src/builtin/dkim.bi
@@ -198,13 +198,13 @@ STRING canon_h, STRING canon_b, STRING headers)
env_get_locus(env, &locus);
if (MF_DEFINED(canon_h)) {
- sig.canon[0] = dkim_str_to_canon_type(canon_h);
+ sig.canon[0] = dkim_str_to_canon_type(canon_h, NULL);
if (sig.canon[0] == DKIM_CANON_ERR)
MF_THROW(mfe_failure,
_("bad canonicalization type: %s"), canon_h);
}
if (MF_DEFINED(canon_b)) {
- sig.canon[1] = dkim_str_to_canon_type(canon_b);
+ sig.canon[1] = dkim_str_to_canon_type(canon_b, NULL);
if (sig.canon[1] == DKIM_CANON_ERR)
MF_THROW(mfe_failure,
_("bad canonicalization type: %s"), canon_b);
@@ -260,12 +260,13 @@ STRING canon_h, STRING canon_b, STRING headers)
while (mu_isblank(*p))
p++;
- trace("%s%s:%u: %s \"%s: %s\"",
+ trace("%s%s:%u: %s %d \"%s: %s\"",
mailfromd_msgid(env_get_context(env)),
locus.beg.mu_file, locus.beg.mu_line,
- msgmod_opcode_str(header_add),
+ msgmod_opcode_str(header_insert),
+ 1,
sighdr, p);
- env_msgmod_append(env, header_add, sighdr, p, 1);
+ env_msgmod_append(env, header_insert, sighdr, p, 1);
free(sighdr);
}
END
@@ -273,6 +274,7 @@ END
MF_VAR(dkim_explanation_code, NUMBER);
MF_VAR(dkim_explanation, STRING);
+MF_DSEXP
MF_DEFUN(dkim_verify, NUMBER, NUMBER nmsg)
{
mu_message_t msg = bi_message_from_descr(env, nmsg);
diff --git a/src/dkim-canonicalize.c b/src/dkim-canonicalize.c
index 42e01413..ff221b7d 100644
--- a/src/dkim-canonicalize.c
+++ b/src/dkim-canonicalize.c
@@ -128,7 +128,13 @@ dkim_canonicalizer(void *xd,
} else if (*iptr == ':') {
*optr++ = *iptr++;
encoder->state = HR_COLON;
- } else if (mu_isheadr(*iptr)) {
+ } else if (mu_isheadr(*iptr) ||
+ /*
+ * Work around the bug in mailutils 3.9:
+ * the MU_CTYPE_HEADR class did not include
+ * underscore.
+ */
+ *iptr == '_') {
*optr++ = mu_tolower(*iptr++);
} else {
iobuf->errcode = MU_ERR_USER0;
@@ -237,14 +243,14 @@ dkim_canonicalizer(void *xd,
break;
case BR_WS:
- if (!mu_isblank(*iptr)) {
+ if (*iptr == '\n') {
+ iptr++;
+ encoder->nlcount++;
+ encoder->state = BR_NL;
+ } else if (!mu_isblank(*iptr)) {
*optr++ = ' ';
encoder->state = BR_INIT;
} else {
- if (*iptr == '\n') {
- encoder->nlcount++;
- encoder->state = BR_NL;
- }
iptr++;
}
break;
diff --git a/src/dkim.c b/src/dkim.c
index bc3c3da8..18ad159b 100644
--- a/src/dkim.c
+++ b/src/dkim.c
@@ -458,14 +458,26 @@ dkim_rsa_sha256_sign(struct rsa_private_key *priv, struct sha256_ctx *ctx,
*/
static char const *dkim_canon_string[] = { "simple", "relaxed", NULL };
+/*
+ * Convert STR to a DKIM_CANON_* constant (return DKIM_CANON_ERR on error).
+ * If ENDP is NULL, STR must be one of the strings from dkim_canon_string.
+ * Otherwise, STR may be followed by '\0' or '/'. The pointer to that
+ * character will be returned in the memory location pointed to by ENDP.
+ */
int
-dkim_str_to_canon_type(char const *str)
+dkim_str_to_canon_type(char const *str, char **endp)
{
int i;
-
- for (i = 0; dkim_canon_string[i]; i++)
- if (strcmp(str, dkim_canon_string[i]) == 0)
- return i;
+ size_t len = strcspn(str, "/");
+ if (endp || str[len] == 0) {
+ for (i = 0; dkim_canon_string[i]; i++)
+ if (len == strlen(dkim_canon_string[i]) &&
+ memcmp(str, dkim_canon_string[i], len) == 0) {
+ if (endp)
+ *endp = (char*)(str + len);
+ return i;
+ }
+ }
return DKIM_CANON_ERR;
}
@@ -595,24 +607,28 @@ dkim_signature_parse(char *str, struct dkim_signature *ret_sig)
*p++ = 0;
if (strcmp(k, "a") == 0) {
sig.a = (char*) mu_strdup(p);
- } if (strcmp(k, "b") == 0) {
+ } else if (strcmp(k, "b") == 0) {
sig.b = (uint8_t*) mu_strdup(p);
} else if (strcmp(k, "bh") == 0) {
sig.bh = (uint8_t*) mu_strdup(p);
} else if (strcmp(k, "q") == 0) {
sig.q = mu_strdup(p);
} else if (strcmp(k, "c") == 0) {
- char *s = strchr(p, '/');
- if (!s) {
+ char *s;
+
+ if ((sig.canon[0] = dkim_str_to_canon_type(p, &s))
+ == DKIM_CANON_ERR) {
rc = -1;
goto end;
}
- *s++ = 0;
- if ((sig.canon[0] = dkim_str_to_canon_type(p)) == DKIM_CANON_ERR ||
- (sig.canon[1] = dkim_str_to_canon_type(s)) == DKIM_CANON_ERR) {
+
+ if (*s == 0)
+ sig.canon[1] = sig.canon[0];
+ else if (*s != '/' ||
+ (sig.canon[1] = dkim_str_to_canon_type(s + 1, NULL)) == DKIM_CANON_ERR) {
rc = -1;
goto end;
- }
+ }
} else if (strcmp(k, "d") == 0) {
sig.d = mu_strdup(p);
} else if (strcmp(k, "s") == 0) {
@@ -1159,7 +1175,7 @@ int dkim_result_trans[] = {
};
static int
-dkim_sig_validate(struct dkim_signature const *sig)
+dkim_sig_validate(struct dkim_signature *sig)
{
if (!sig->a
|| !sig->b
@@ -1167,18 +1183,19 @@ dkim_sig_validate(struct dkim_signature const *sig)
|| !sig->d
|| !sig->h
|| !sig->s
- || !sig->q
|| !sig->v) {
return DKIM_EXPL_SIG_MISS;
}
-
+
if (strcmp(sig->v, DKIM_VERSION))
return DKIM_EXPL_BAD_VERSION;
if (strcmp(sig->a, DKIM_ALGORITHM))
return DKIM_EXPL_BAD_ALGORITHM;
- if (strcmp(sig->q, DKIM_QUERY_METHOD))
+ if (!sig->q)
+ sig->q = mu_strdup(DKIM_QUERY_METHOD);
+ else if (strcmp(sig->q, DKIM_QUERY_METHOD))
return DKIM_EXPL_BAD_QUERY;
if (sig->i) {
@@ -1191,7 +1208,7 @@ dkim_sig_validate(struct dkim_signature const *sig)
dlen = strlen(sig->d);
if (!(dlen <= ilen &&
mu_c_strcasecmp(sig->d, p + ilen - dlen) == 0 &&
- sig->d[ilen - dlen - 1] == '.'))
+ (p[ilen - dlen - 1] == '.' || p[ilen - dlen - 1] == '@')))
return DKIM_EXPL_DOMAIN_MISMATCH;
}
@@ -1261,14 +1278,25 @@ static int
pubkey_validate(mu_assoc_t a, struct dkim_signature const *sig)
{
char *s;
+ size_t n;
+
+ if ((s = mu_assoc_get(a, "v")) != NULL &&
+ strcmp(s, DKIM_KEYRECORD_VERSION))
+ return DKIM_EXPL_KEY_SYNTAX;
+
if ((s = mu_assoc_get(a, "p")) == NULL)
return DKIM_EXPL_KEY_SYNTAX;
if (s[0] == 0)
return DKIM_EXPL_KEY_REVOKED;
-
+
+ n = strcspn(sig->a, "-");
+ if ((s = mu_assoc_get(a, "k")) != NULL &&
+ !(n == strlen(s) && memcmp(s, sig->a, n) == 0))
+ return DKIM_EXPL_BAD_ALGORITHM;
+
if ((s = mu_assoc_get(a, "h")) != NULL &&
- !dkim_header_list_match(s, sig->a))
+ !dkim_header_list_match(s, sig->a + n + 1))
return DKIM_EXPL_BAD_ALGORITHM;
return DKIM_EXPL_OK;
}
diff --git a/src/dkim.h b/src/dkim.h
index aaa83a93..7b52d11f 100644
--- a/src/dkim.h
+++ b/src/dkim.h
@@ -27,6 +27,7 @@ enum {
};
#define DKIM_VERSION "1"
+#define DKIM_KEYRECORD_VERSION "DKIM1"
#define DKIM_SIGNATURE_HEADER "DKIM-Signature"
#define DKIM_QUERY_METHOD "dns/txt"
#define DKIM_ALGORITHM "rsa-sha256"
@@ -52,7 +53,7 @@ struct dkim_signature {
};
/* Convert canonicalization type to a DKIM_CANON_ constant. */
-int dkim_str_to_canon_type(char const *str);
+int dkim_str_to_canon_type(char const *str, char **endp);
/*
* Create canonicalizer filter for STREAM. Use canonicalization types

Return to:

Send suggestions and report system problems to the System administrator.