}
+static int
+pdkim_keyname_to_keytype(const uschar * s)
+{
+for (int i = 0; i < nelem(pdkim_keytypes); i++)
+ if (Ustrcmp(s, pdkim_keytypes[i]) == 0) return i;
+return -1;
+}
+
int
pdkim_hashname_to_hashtype(const uschar * s, unsigned len)
{
static pdkim_stringlist *
pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
{
-pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
+pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), FALSE);
memset(new_entry, 0, sizeof(pdkim_stringlist));
new_entry->value = string_copy(str);
{
BOOL past_field_name = FALSE;
BOOL seen_wsp = FALSE;
-uschar * relaxed = store_get(len+3);
+uschar * relaxed = store_get(len+3, TRUE); /* tainted */
uschar * q = relaxed;
for (const uschar * p = header; p - header < len; p++)
int nchar = 0;
uschar * q;
const uschar * p = str;
-uschar * n = store_get(Ustrlen(str)+1);
+uschar * n = store_get(Ustrlen(str)+1, TRUE);
*n = '\0';
q = n;
BOOL in_b_val = FALSE;
int where = PDKIM_HDR_LIMBO;
-sig = store_get(sizeof(pdkim_signature));
+sig = store_get(sizeof(pdkim_signature), FALSE);
memset(sig, 0, sizeof(pdkim_signature));
sig->bodylength = -1;
sig->keytype = -1;
sig->hashtype = -1;
-q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
+q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, TRUE); /* tainted */
for (uschar * p = raw_hdr; ; p++)
{
uschar * elem;
if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
- for (int i = 0; i < nelem(pdkim_keytypes); i++)
- if (Ustrcmp(elem, pdkim_keytypes[i]) == 0)
- { sig->keytype = i; break; }
+ sig->keytype = pdkim_keyname_to_keytype(elem);
if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
for (int i = 0; i < nelem(pdkim_hashes); i++)
if (Ustrcmp(elem, pdkim_hashes[i].dkim_hashname) == 0)
int sep = ';';
pdkim_pubkey * pub;
-pub = store_get(sizeof(pdkim_pubkey));
+pub = store_get(sizeof(pdkim_pubkey), TRUE); /* tainted */
memset(pub, 0, sizeof(pdkim_pubkey));
while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
instead. Assume writing on the sig is ok in that case. */
if (sig->keytype < 0)
- {
- for(int i = 0; i < nelem(pdkim_keytypes); i++)
- if (Ustrcmp(p->keytype, pdkim_keytypes[i]) == 0)
- { sig->keytype = i; goto k_ok; }
- DEBUG(D_acl) debug_printf("verify_init: unhandled keytype %s\n", p->keytype);
- sig->verify_status = PDKIM_VERIFY_INVALID;
- sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
- return NULL;
- }
-k_ok:
+ if ((sig->keytype = pdkim_keyname_to_keytype(p->keytype)) < 0)
+ {
+ DEBUG(D_acl) debug_printf("verify_init: unhandled keytype %s\n", p->keytype);
+ sig->verify_status = PDKIM_VERIFY_INVALID;
+ sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
+ return NULL;
+ }
if (sig->keytype == KEYTYPE_ED25519)
check_bare_ed25519_pubkey(p);
}
+/* -------------------------------------------------------------------------- */
+/* Sort and filter the sigs developed from the message */
+
+static pdkim_signature *
+sort_sig_methods(pdkim_signature * siglist)
+{
+pdkim_signature * yield, ** ss;
+const uschar * prefs;
+uschar * ele;
+int sep;
+
+if (!siglist) return NULL;
+
+/* first select in order of hashtypes */
+DEBUG(D_acl) debug_printf("PDKIM: dkim_verify_hashes '%s'\n", dkim_verify_hashes);
+for (prefs = dkim_verify_hashes, sep = 0, yield = NULL, ss = &yield;
+ ele = string_nextinlist(&prefs, &sep, NULL, 0); )
+ {
+ int i = pdkim_hashname_to_hashtype(CUS ele, 0);
+ for (pdkim_signature * s = siglist, * next, ** prev = &siglist; s;
+ s = next)
+ {
+ next = s->next;
+ if (s->hashtype == i)
+ { *prev = next; s->next = NULL; *ss = s; ss = &s->next; }
+ else
+ prev = &s->next;
+ }
+ }
+
+/* then in order of keytypes */
+siglist = yield;
+DEBUG(D_acl) debug_printf("PDKIM: dkim_verify_keytypes '%s'\n", dkim_verify_keytypes);
+for (prefs = dkim_verify_keytypes, sep = 0, yield = NULL, ss = &yield;
+ ele = string_nextinlist(&prefs, &sep, NULL, 0); )
+ {
+ int i = pdkim_keyname_to_keytype(CUS ele);
+ for (pdkim_signature * s = siglist, * next, ** prev = &siglist; s;
+ s = next)
+ {
+ next = s->next;
+ if (s->keytype == i)
+ { *prev = next; s->next = NULL; *ss = s; ss = &s->next; }
+ else
+ prev = &s->next;
+ }
+ }
+
+DEBUG(D_acl) for (pdkim_signature * s = yield; s; s = s->next)
+ debug_printf(" retain d=%s s=%s a=%s\n",
+ s->domain, s->selector, dkim_sig_to_a_tag(s));
+return yield;
+}
+
+
/* -------------------------------------------------------------------------- */
DLLEXPORT int
pdkim_finish_bodyhash(ctx);
+/* Sort and filter the recived signatures */
+
+if (!(ctx->flags & PDKIM_MODE_SIGN))
+ ctx->sig = sort_sig_methods(ctx->sig);
+
if (!ctx->sig)
{
DEBUG(D_acl) debug_printf("PDKIM: no signatures\n");
}
/*XXX The hash of the headers is needed for GCrypt (for which we can do RSA
- suging only, as it happens) and for either GnuTLS and OpenSSL when we are
+ signing only, as it happens) and for either GnuTLS and OpenSSL when we are
signing with EC (specifically, Ed25519). The former is because the GCrypt
signing operation is pure (does not do its own hash) so we must hash. The
latter is because we (stupidly, but this is what the IETF draft is saying)
/* Import private key, including the keytype which we need for building
the signature header */
-/*XXX extend for non-RSA algos */
if ((*err = exim_dkim_signing_init(CUS sig->privkey, &sctx)))
{
log_write(0, LOG_MAIN|LOG_PANIC, "signing_init: %s", *err);
{
sig->verify_status = PDKIM_VERIFY_PASS;
verify_pass = TRUE;
+ if (dkim_verify_minimal) break;
}
NEXT_VERIFY:
/* -------------------------------------------------------------------------- */
DLLEXPORT pdkim_ctx *
-pdkim_init_verify(uschar * (*dns_txt_callback)(uschar *), BOOL dot_stuffing)
+pdkim_init_verify(uschar * (*dns_txt_callback)(const uschar *), BOOL dot_stuffing)
{
pdkim_ctx * ctx;
-ctx = store_get(sizeof(pdkim_ctx));
+ctx = store_get(sizeof(pdkim_ctx), FALSE);
memset(ctx, 0, sizeof(pdkim_ctx));
if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
-ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
+/* The line-buffer is for message data, hence tainted */
+ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
ctx->dns_txt_callback = dns_txt_callback;
return ctx;
/* Allocate & init one signature struct */
-sig = store_get(sizeof(pdkim_signature));
+sig = store_get(sizeof(pdkim_signature), FALSE);
memset(sig, 0, sizeof(pdkim_signature));
sig->bodylength = -1;
DEBUG(D_receive) debug_printf("PDKIM: new bodyhash %d/%d/%ld\n",
hashtype, canon_method, bodylength);
-b = store_get(sizeof(pdkim_bodyhash));
+b = store_get(sizeof(pdkim_bodyhash), FALSE);
b->next = ctx->bodyhash;
b->hashtype = hashtype;
b->canon_method = canon_method;
void
pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
- uschar * (*dns_txt_callback)(uschar *))
+ uschar * (*dns_txt_callback)(const uschar *))
{
memset(ctx, 0, sizeof(pdkim_ctx));
ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
-ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
+/* The line buffer is for message data, hence tainted */
+ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
}