DKIM: preferences for verify algorithms
[exim.git] / src / src / pdkim / pdkim.c
index 594af03c526c028b0065be196984db6878623d74..79e7c633d7f895d473cd171ba05109191ec00bed 100644 (file)
@@ -26,8 +26,8 @@
 
 #ifndef DISABLE_DKIM   /* entire file */
 
 
 #ifndef DISABLE_DKIM   /* entire file */
 
-#ifndef SUPPORT_TLS
-# error Need SUPPORT_TLS for DKIM
+#ifdef DISABLE_TLS
+# error Must not DISABLE_TLS, for DKIM
 #endif
 
 #include "crypt_ver.h"
 #endif
 
 #include "crypt_ver.h"
@@ -121,12 +121,19 @@ return string_sprintf("%s-%s",
 }
 
 
 }
 
 
+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)
 {
 int
 pdkim_hashname_to_hashtype(const uschar * s, unsigned len)
 {
-int i;
 if (!len) len = Ustrlen(s);
 if (!len) len = Ustrlen(s);
-for (i = 0; i < nelem(pdkim_hashes); i++)
+for (int i = 0; i < nelem(pdkim_hashes); i++)
   if (Ustrncmp(s, pdkim_hashes[i].dkim_hashname, len) == 0)
     return i;
 return -1;
   if (Ustrncmp(s, pdkim_hashes[i].dkim_hashname, len) == 0)
     return i;
 return -1;
@@ -136,9 +143,8 @@ void
 pdkim_cstring_to_canons(const uschar * s, unsigned len,
   int * canon_head, int * canon_body)
 {
 pdkim_cstring_to_canons(const uschar * s, unsigned len,
   int * canon_head, int * canon_body)
 {
-int i;
 if (!len) len = Ustrlen(s);
 if (!len) len = Ustrlen(s);
-for (i = 0; pdkim_combined_canons[i].str; i++)
+for (int i = 0; pdkim_combined_canons[i].str; i++)
   if (  Ustrncmp(s, pdkim_combined_canons[i].str, len) == 0
      && len == Ustrlen(pdkim_combined_canons[i].str))
     {
   if (  Ustrncmp(s, pdkim_combined_canons[i].str, len) == 0
      && len == Ustrlen(pdkim_combined_canons[i].str))
     {
@@ -205,8 +211,7 @@ switch(status)
 void
 pdkim_quoteprint(const uschar *data, int len)
 {
 void
 pdkim_quoteprint(const uschar *data, int len)
 {
-int i;
-for (i = 0; i < len; i++)
+for (int i = 0; i < len; i++)
   {
   const int c = data[i];
   switch (c)
   {
   const int c = data[i];
   switch (c)
@@ -231,8 +236,7 @@ debug_printf("\n");
 void
 pdkim_hexprint(const uschar *data, int len)
 {
 void
 pdkim_hexprint(const uschar *data, int len)
 {
-int i;
-if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
+if (data) for (int i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
 else debug_printf("<NULL>");
 debug_printf("\n");
 }
 else debug_printf("<NULL>");
 debug_printf("\n");
 }
@@ -242,7 +246,7 @@ debug_printf("\n");
 static pdkim_stringlist *
 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
 {
 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);
 
 memset(new_entry, 0, sizeof(pdkim_stringlist));
 new_entry->value = string_copy(str);
@@ -332,11 +336,10 @@ pdkim_relax_header_n(const uschar * header, int len, BOOL append_crlf)
 {
 BOOL past_field_name = FALSE;
 BOOL seen_wsp = FALSE;
 {
 BOOL past_field_name = FALSE;
 BOOL seen_wsp = FALSE;
-const uschar * p;
-uschar * relaxed = store_get(len+3);
+uschar * relaxed = store_get(len+3, TRUE);     /* tainted */
 uschar * q = relaxed;
 
 uschar * q = relaxed;
 
-for (p = header; p - header < len; p++)
+for (const uschar * p = header; p - header < len; p++)
   {
   uschar c = *p;
 
   {
   uschar c = *p;
 
@@ -413,7 +416,7 @@ pdkim_decode_qp(const uschar * str)
 int nchar = 0;
 uschar * q;
 const uschar * p = str;
 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;
 
 *n = '\0';
 q = n;
@@ -450,7 +453,7 @@ b->len = dlen;
 uschar *
 pdkim_encode_base64(blob * b)
 {
 uschar *
 pdkim_encode_base64(blob * b)
 {
-return b64encode(b->data, b->len);
+return b64encode(CUS b->data, b->len);
 }
 
 
 }
 
 
@@ -463,15 +466,14 @@ static pdkim_signature *
 pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
 {
 pdkim_signature * sig;
 pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
 {
 pdkim_signature * sig;
-uschar *p, *q;
+uschar *q;
 gstring * cur_tag = NULL;
 gstring * cur_val = NULL;
 BOOL past_hname = FALSE;
 BOOL in_b_val = FALSE;
 int where = PDKIM_HDR_LIMBO;
 gstring * cur_tag = NULL;
 gstring * cur_val = NULL;
 BOOL past_hname = FALSE;
 BOOL in_b_val = FALSE;
 int where = PDKIM_HDR_LIMBO;
-int i;
 
 
-sig = store_get(sizeof(pdkim_signature));
+sig = store_get(sizeof(pdkim_signature), FALSE);
 memset(sig, 0, sizeof(pdkim_signature));
 sig->bodylength = -1;
 
 memset(sig, 0, sizeof(pdkim_signature));
 sig->bodylength = -1;
 
@@ -480,9 +482,9 @@ sig->version = 0;
 sig->keytype = -1;
 sig->hashtype = -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 (p = raw_hdr; ; p++)
+for (uschar * p = raw_hdr; ; p++)
   {
   char c = *p;
 
   {
   char c = *p;
 
@@ -567,11 +569,9 @@ for (p = raw_hdr; ; p++)
            uschar * elem;
 
            if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
            uschar * elem;
 
            if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
-             for(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)))
            if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
-             for (i = 0; i < nelem(pdkim_hashes); i++)
+             for (int i = 0; i < nelem(pdkim_hashes); i++)
                if (Ustrcmp(elem, pdkim_hashes[i].dkim_hashname) == 0)
                  { sig->hashtype = i; break; }
            }
                if (Ustrcmp(elem, pdkim_hashes[i].dkim_hashname) == 0)
                  { sig->hashtype = i; break; }
            }
@@ -581,7 +581,7 @@ for (p = raw_hdr; ; p++)
                                    &sig->canon_headers, &sig->canon_body);
            break;
          case 'q':                             /* Query method (for pubkey)*/
                                    &sig->canon_headers, &sig->canon_body);
            break;
          case 'q':                             /* Query method (for pubkey)*/
-           for (i = 0; pdkim_querymethods[i]; i++)
+           for (int i = 0; pdkim_querymethods[i]; i++)
              if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
                {
                sig->querymethod = i;   /* we never actually use this */
              if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
                {
                sig->querymethod = i;   /* we never actually use this */
@@ -662,7 +662,7 @@ const uschar * ele;
 int sep = ';';
 pdkim_pubkey * pub;
 
 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)))
 memset(pub, 0, sizeof(pdkim_pubkey));
 
 while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
@@ -730,7 +730,6 @@ if (b->canon_method == PDKIM_CANON_RELAXED)
   if (!relaxed_data)
     {
     BOOL seen_wsp = FALSE;
   if (!relaxed_data)
     {
     BOOL seen_wsp = FALSE;
-    const uschar * p, * r;
     int q = 0;
 
     /* We want to be able to free this else we allocate
     int q = 0;
 
     /* We want to be able to free this else we allocate
@@ -741,7 +740,7 @@ if (b->canon_method == PDKIM_CANON_RELAXED)
     relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
     relaxed_data->data = US (relaxed_data+1);
 
     relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
     relaxed_data->data = US (relaxed_data+1);
 
-    for (p = orig_data->data, r = p + orig_data->len; p < r; p++)
+    for (const uschar * p = orig_data->data, * r = p + orig_data->len; p < r; p++)
       {
       char c = *p;
       if (c == '\r')
       {
       char c = *p;
       if (c == '\r')
@@ -788,10 +787,7 @@ return relaxed_data;
 static void
 pdkim_finish_bodyhash(pdkim_ctx * ctx)
 {
 static void
 pdkim_finish_bodyhash(pdkim_ctx * ctx)
 {
-pdkim_bodyhash * b;
-pdkim_signature * sig;
-
-for (b = ctx->bodyhash; b; b = b->next)                /* Finish hashes */
+for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)     /* Finish hashes */
   {
   DEBUG(D_acl) debug_printf("PDKIM: finish bodyhash %d/%d/%ld len %ld\n",
            b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes);
   {
   DEBUG(D_acl) debug_printf("PDKIM: finish bodyhash %d/%d/%ld len %ld\n",
            b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes);
@@ -799,9 +795,9 @@ for (b = ctx->bodyhash; b; b = b->next)             /* Finish hashes */
   }
 
 /* Traverse all signatures */
   }
 
 /* Traverse all signatures */
-for (sig = ctx->sig; sig; sig = sig->next)
+for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
   {
   {
-  b = sig->calc_body_hash;
+  pdkim_bodyhash * b = sig->calc_body_hash;
 
   DEBUG(D_acl)
     {
 
   DEBUG(D_acl)
     {
@@ -849,15 +845,13 @@ for (sig = ctx->sig; sig; sig = sig->next)
 static void
 pdkim_body_complete(pdkim_ctx * ctx)
 {
 static void
 pdkim_body_complete(pdkim_ctx * ctx)
 {
-pdkim_bodyhash * b;
-
 /* In simple body mode, if any empty lines were buffered,
 replace with one. rfc 4871 3.4.3 */
 /*XXX checking the signed-body-bytes is a gross hack; I think
 it indicates that all linebreaks should be buffered, including
 the one terminating a text line */
 
 /* In simple body mode, if any empty lines were buffered,
 replace with one. rfc 4871 3.4.3 */
 /*XXX checking the signed-body-bytes is a gross hack; I think
 it indicates that all linebreaks should be buffered, including
 the one terminating a text line */
 
-for (b = ctx->bodyhash; b; b = b->next)
+for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
   if (  b->canon_method == PDKIM_CANON_SIMPLE
      && b->signed_body_bytes == 0
      && b->num_buffered_blanklines > 0
   if (  b->canon_method == PDKIM_CANON_SIMPLE
      && b->signed_body_bytes == 0
      && b->num_buffered_blanklines > 0
@@ -878,7 +872,6 @@ static void
 pdkim_bodyline_complete(pdkim_ctx * ctx)
 {
 blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
 pdkim_bodyline_complete(pdkim_ctx * ctx)
 {
 blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
-pdkim_bodyhash * b;
 blob * rnl = NULL;
 blob * rline = NULL;
 
 blob * rnl = NULL;
 blob * rline = NULL;
 
@@ -902,12 +895,13 @@ if (ctx->flags & PDKIM_DOT_TERM)
 /* Empty lines need to be buffered until we find a non-empty line */
 if (memcmp(line.data, "\r\n", 2) == 0)
   {
 /* Empty lines need to be buffered until we find a non-empty line */
 if (memcmp(line.data, "\r\n", 2) == 0)
   {
-  for (b = ctx->bodyhash; b; b = b->next) b->num_buffered_blanklines++;
+  for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
+    b->num_buffered_blanklines++;
   goto all_skip;
   }
 
 /* Process line for each bodyhash separately */
   goto all_skip;
   }
 
 /* Process line for each bodyhash separately */
-for (b = ctx->bodyhash; b; b = b->next)
+for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
   {
   if (b->canon_method == PDKIM_CANON_RELAXED)
     {
   {
   if (b->canon_method == PDKIM_CANON_RELAXED)
     {
@@ -956,9 +950,6 @@ return;
 static int
 pdkim_header_complete(pdkim_ctx * ctx)
 {
 static int
 pdkim_header_complete(pdkim_ctx * ctx)
 {
-pdkim_signature * sig, * last_sig;
-
-/* Special case: The last header can have an extra \r appended */
 if ( (ctx->cur_header->ptr > 1) &&
      (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
   --ctx->cur_header->ptr;
 if ( (ctx->cur_header->ptr > 1) &&
      (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
   --ctx->cur_header->ptr;
@@ -973,7 +964,7 @@ if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
 
 /* SIGNING -------------------------------------------------------------- */
 if (ctx->flags & PDKIM_MODE_SIGN)
 
 /* SIGNING -------------------------------------------------------------- */
 if (ctx->flags & PDKIM_MODE_SIGN)
-  for (sig = ctx->sig; sig; sig = sig->next)                   /* Traverse all signatures */
+  for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)  /* Traverse all signatures */
 
     /* Add header to the signed headers list (in reverse order) */
     sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
 
     /* Add header to the signed headers list (in reverse order) */
     sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
@@ -993,6 +984,7 @@ else
                  DKIM_SIGNATURE_HEADERNAME,
                  Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
     {
                  DKIM_SIGNATURE_HEADERNAME,
                  Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
     {
+    pdkim_signature * sig, * last_sig;
     /* Create and chain new signature block.  We could error-check for all
     required tags here, but prefer to create the internal sig and expicitly
     fail verification of it later. */
     /* Create and chain new signature block.  We could error-check for all
     required tags here, but prefer to create the internal sig and expicitly
     fail verification of it later. */
@@ -1035,15 +1027,14 @@ return PDKIM_OK;
 DLLEXPORT int
 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
 {
 DLLEXPORT int
 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
 {
-int p, rc;
-
 /* Alternate EOD signal, used in non-dotstuffing mode */
 if (!data)
   pdkim_body_complete(ctx);
 
 /* Alternate EOD signal, used in non-dotstuffing mode */
 if (!data)
   pdkim_body_complete(ctx);
 
-else for (p = 0; p < len; p++)
+else for (int p = 0; p < len; p++)
   {
   uschar c = data[p];
   {
   uschar c = data[p];
+  int rc;
 
   if (ctx->flags & PDKIM_PAST_HDRS)
     {
 
   if (ctx->flags & PDKIM_PAST_HDRS)
     {
@@ -1426,17 +1417,13 @@ time we do not have a signature so we must interpret the pubkey k= tag
 instead.  Assume writing on the sig is ok in that case. */
 
 if (sig->keytype < 0)
 instead.  Assume writing on the sig is ok in that case. */
 
 if (sig->keytype < 0)
-  {
-  int i;
-  for(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);
 
 if (sig->keytype == KEYTYPE_ED25519)
   check_bare_ed25519_pubkey(p);
@@ -1456,14 +1443,67 @@ return 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_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
   const uschar ** err)
 {
 /* -------------------------------------------------------------------------- */
 
 DLLEXPORT int
 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
   const uschar ** err)
 {
-pdkim_bodyhash * b;
-pdkim_signature * sig;
 BOOL verify_pass = FALSE;
 
 /* Check if we must still flush a (partial) header. If that is the
 BOOL verify_pass = FALSE;
 
 /* Check if we must still flush a (partial) header. If that is the
@@ -1477,7 +1517,7 @@ if (ctx->cur_header && ctx->cur_header->ptr > 0)
   if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
     return rc;
 
   if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
     return rc;
 
-  for (b = ctx->bodyhash; b; b = b->next)
+  for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)
     rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
   if (rnl) store_free(rnl);
   }
     rnl = pdkim_update_ctx_bodyhash(b, &lineending, rnl);
   if (rnl) store_free(rnl);
   }
@@ -1490,6 +1530,11 @@ have a hash to do for ARC. */
 
 pdkim_finish_bodyhash(ctx);
 
 
 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");
 if (!ctx->sig)
   {
   DEBUG(D_acl) debug_printf("PDKIM: no signatures\n");
@@ -1497,7 +1542,7 @@ if (!ctx->sig)
   return PDKIM_OK;
   }
 
   return PDKIM_OK;
   }
 
-for (sig = ctx->sig; sig; sig = sig->next)
+for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
   {
   hctx hhash_ctx;
   uschar * sig_hdr = US"";
   {
   hctx hhash_ctx;
   uschar * sig_hdr = US"";
@@ -1514,7 +1559,7 @@ for (sig = ctx->sig; sig; sig = sig->next)
     }
 
   /*XXX The hash of the headers is needed for GCrypt (for which we can do RSA
     }
 
   /*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)
   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)
@@ -1561,7 +1606,6 @@ for (sig = ctx->sig; sig; sig = sig->next)
   if (ctx->flags & PDKIM_MODE_SIGN)
     {
     gstring * g = NULL;
   if (ctx->flags & PDKIM_MODE_SIGN)
     {
     gstring * g = NULL;
-    pdkim_stringlist *p;
     const uschar * l;
     uschar * s;
     int sep = 0;
     const uschar * l;
     uschar * s;
     int sep = 0;
@@ -1569,7 +1613,6 @@ for (sig = ctx->sig; sig; sig = sig->next)
     /* Import private key, including the keytype which we need for building
     the signature header  */
 
     /* 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);
     if ((*err = exim_dkim_signing_init(CUS sig->privkey, &sctx)))
       {
       log_write(0, LOG_MAIN|LOG_PANIC, "signing_init: %s", *err);
@@ -1577,8 +1620,8 @@ for (sig = ctx->sig; sig; sig = sig->next)
       }
     sig->keytype = sctx.keytype;
 
       }
     sig->keytype = sctx.keytype;
 
-    for (sig->headernames = NULL,              /* Collected signed header names */
-         p = sig->headers; p; p = p->next)
+    sig->headernames = NULL;                   /* Collected signed header names */
+    for (pdkim_stringlist * p = sig->headers; p; p = p->next)
       {
       uschar * rh = p->value;
 
       {
       uschar * rh = p->value;
 
@@ -1625,12 +1668,11 @@ for (sig = ctx->sig; sig; sig = sig->next)
     {
     uschar * p = sig->headernames;
     uschar * q;
     {
     uschar * p = sig->headernames;
     uschar * q;
-    pdkim_stringlist * hdrs;
 
     if (p)
       {
       /* clear tags */
 
     if (p)
       {
       /* clear tags */
-      for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
+      for (pdkim_stringlist * hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
        hdrs->tag = 0;
 
       p = string_copy(p);
        hdrs->tag = 0;
 
       p = string_copy(p);
@@ -1640,7 +1682,7 @@ for (sig = ctx->sig; sig; sig = sig->next)
          *q = '\0';
 
   /*XXX walk the list of headers in same order as received. */
          *q = '\0';
 
   /*XXX walk the list of headers in same order as received. */
-       for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
+       for (pdkim_stringlist * hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
          if (  hdrs->tag == 0
             && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
             && (hdrs->value)[Ustrlen(p)] == ':'
          if (  hdrs->tag == 0
             && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
             && (hdrs->value)[Ustrlen(p)] == ':'
@@ -1851,6 +1893,7 @@ for (sig = ctx->sig; sig; sig = sig->next)
       {
       sig->verify_status = PDKIM_VERIFY_PASS;
       verify_pass = TRUE;
       {
       sig->verify_status = PDKIM_VERIFY_PASS;
       verify_pass = TRUE;
+      if (dkim_verify_minimal) break;
       }
 
 NEXT_VERIFY:
       }
 
 NEXT_VERIFY:
@@ -1881,15 +1924,16 @@ return ctx->flags & PDKIM_MODE_SIGN  ||  verify_pass
 /* -------------------------------------------------------------------------- */
 
 DLLEXPORT pdkim_ctx *
 /* -------------------------------------------------------------------------- */
 
 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;
 
 {
 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;
 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;
 ctx->dns_txt_callback = dns_txt_callback;
 
 return ctx;
@@ -1911,7 +1955,7 @@ if (!domain || !selector || !privkey)
 
 /* Allocate & init one signature struct */
 
 
 /* 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;
 memset(sig, 0, sizeof(pdkim_signature));
 
 sig->bodylength = -1;
@@ -1997,7 +2041,7 @@ for (b = ctx->bodyhash; b; b = b->next)
 
 DEBUG(D_receive) debug_printf("PDKIM: new bodyhash %d/%d/%ld\n",
                              hashtype, canon_method, bodylength);
 
 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;
 b->next = ctx->bodyhash;
 b->hashtype = hashtype;
 b->canon_method = canon_method;
@@ -2037,11 +2081,12 @@ return b;
 
 void
 pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
 
 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;
 {
 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;
 }
 
 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
 }