[exim-cvs] DKIM: preferences for verify algorithms

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] DKIM: preferences for verify algorithms
Gitweb: https://git.exim.org/exim.git/commitdiff/042e558f346b01902dd414206a047fa47b686f0b
Commit:     042e558f346b01902dd414206a047fa47b686f0b
Parent:     dbbf21a75d225871cb7a44878ece42c5d79a1a2c
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sat Aug 10 17:58:22 2019 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sun Aug 11 19:26:43 2019 +0100


    DKIM: preferences for verify algorithms
---
 doc/doc-docbook/spec.xfpt           | 60 ++++++++++++++++++++----
 doc/doc-txt/NewStuff                |  2 +
 doc/doc-txt/OptionLists.txt         |  3 ++
 src/src/globals.c                   |  3 ++
 src/src/globals.h                   |  3 ++
 src/src/pdkim/pdkim.c               | 93 +++++++++++++++++++++++++++++++------
 src/src/pdkim/pdkim.h               |  5 +-
 src/src/readconf.c                  |  3 ++
 test/confs/4509                     | 28 +++++++++++
 test/confs/4520                     |  3 ++
 test/confs/4541                     |  1 +
 test/log/4509                       |  5 ++
 test/log/4541                       | 28 +++++++++++
 test/mail/4541.a                    | 26 +++++++++++
 test/mail/4541.b                    | 26 +++++++++++
 test/scripts/4500-DKIM/4509         | 41 ++++++++++++++++
 test/scripts/4540-DKIM-Ed25519/4541 | 30 ++++++++++++
 17 files changed, 331 insertions(+), 29 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index aa39965..8bba6fe 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -14347,7 +14347,9 @@ listed in more than one group.
See also the &'Policy controls'& section above.

 .table2
-.row &%dkim_verify_signers%&         "DKIM domain for which DKIM ACL is run"
+.row &%dkim_verify_hashes%&          "DKIM hash methods accepted for signatures"
+.row &%dkim_verify_keytypes%&        "DKIM key types accepted for signatures"
+.row &%dkim_verify_signers%&         "DKIM domains for which DKIM ACL is run"
 .row &%host_lookup%&                 "host name looked up for these hosts"
 .row &%host_lookup_order%&           "order of DNS and local name lookups"
 .row &%recipient_unqualified_hosts%& "may send unqualified recipients"
@@ -15092,6 +15094,27 @@ etc. are ignored. If IP literals are enabled, the &(ipliteral)& router declines
 to handle IPv6 literal addresses.



+.new
+.option dkim_verify_hashes main "string list" "sha256 : sha512 : sha1"
+.cindex DKIM "selecting signature algorithms"
+This option gives a list of hash types which are acceptable in signatures,
+and an order of processing.
+Signatures with algorithms not in the list will be ignored.
+
+Note that the presence of sha1 violates RFC 8301.
+Signatures using the rsa-sha1 are however (as of writing) still common.
+The default inclusion of sha1 may be dropped in a future release.
+
+.option dkim_verify_keytypes main "string list" "ed25519 : rsa"
+This option gives a list of key types which are acceptable in signatures,
+and an order of processing.
+Signatures with algorithms not in the list will be ignored.
+
+.option dkim_verify_minimal main boolean false
+If set to true, verification of signatures will terminate after the
+first success.
+.wen
+
.option dkim_verify_signers main "domain list&!!" $dkim_signers
.cindex DKIM "controlling calls to the ACL"
This option gives a list of DKIM domains for which the DKIM ACL is run.
@@ -39913,15 +39936,28 @@ RFC 6376 lists these tags as RECOMMENDED.

Verification of DKIM signatures in SMTP incoming email is done for all
messages for which an ACL control &%dkim_disable_verify%& has not been set.
+.new
+.cindex DKIM "selecting signature algorithms"
+Individual classes of signature algorithm can be ignored by changing
+the main options &%dkim_verify_hashes%& or &%dkim_verify_keytypes%&.
+The &%dkim_verify_minimal%& option can be set to cease verification
+processing for a message once the first passing signature is found.
+.wen
+
.cindex authentication "expansion item"
Performing verification sets up information used by the
&$authresults$& expansion item.

-The results of that verification are then made available to the
+.new
+For most purposes the default option settings suffice and the remainder
+of this section can be ignored.
+.wen
+
+The results of verification are made available to the
&%acl_smtp_dkim%& ACL, which can examine and modify them.
-By default, this ACL is called once for each
-syntactically(!) correct signature in the incoming message.
A missing ACL definition defaults to accept.
+By default, the ACL is called once for each
+syntactically(!) correct signature in the incoming message.
If any ACL call does not accept, the message is not accepted.
If a cutthrough delivery was in progress for the message, that is
summarily dropped (having wasted the transmission effort).
@@ -39932,11 +39968,11 @@ containing the signature status and its details are set up during the
runtime of the ACL.

Calling the ACL only for existing signatures is not sufficient to build
-more advanced policies. For that reason, the global option
-&%dkim_verify_signers%&, and a global expansion variable
+more advanced policies. For that reason, the main option
+&%dkim_verify_signers%&, and an expansion variable
&%$dkim_signers%& exist.

-The global option &%dkim_verify_signers%& can be set to a colon-separated
+The main option &%dkim_verify_signers%& can be set to a colon-separated
list of DKIM domains or identities for which the ACL &%acl_smtp_dkim%& is
called. It is expanded when the message has been received. At this point,
the expansion variable &%$dkim_signers%& already contains a colon-separated
@@ -39974,7 +40010,7 @@ If multiple signatures match a domain (or identity), the ACL is called once
for each matching signature.


-Inside the &%acl_smtp_dkim%&, the following expansion variables are
+Inside the DKIM ACL, the following expansion variables are
available (from most to least important):


@@ -40068,8 +40104,12 @@ DKIM signatures identified as having been signed with historic
algorithms (currently, rsa-sha1) have permanently failed evaluation
.endd

-To enforce this you must have a DKIM ACL which checks this variable
-and overwrites the &$dkim_verify_status$& variable as discussed above.
+To enforce this you must either have a DKIM ACL which checks this variable
+and overwrites the &$dkim_verify_status$& variable as discussed above,
+.new
+or have set the main option &%dkim_verify_hashes%& to exclude
+processing of such signatures.
+.wen

.vitem &%$dkim_canon_body%&
The body canonicalization method. One of 'relaxed' or 'simple'.
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index bcfbe7c..8577f6d 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -33,6 +33,8 @@ Version 4.93

10. The spf lookup now supports IPv6.

+11. Main options for DKIM verify to filter hash and key types.
+

 Version 4.92
 --------------
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index 1622467..abc09ec 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -171,6 +171,9 @@ dkim_selector                        string*         unset         smtp
 dkim_sign_headers                    string*         (RFC4871)     smtp              4.70
 dkim_strict                          string*         unset         smtp              4.70
 dkim_timestamps                      integer*        unset         smtp              4.92
+dkim_verify_hashes                   string          sha256:sha512:sha1 main         4.93
+dkim_verify_keytypes                 string          ed25519:rsa        main         4.93
+dkim_verify_minimal                  boolean         false              main         4.93
 dkim_verify_signers                  string*         $dkim_signers main              4.70
 directory                            string*         unset         appendfile
 directory_file                       string*         +             appendfile
diff --git a/src/src/globals.c b/src/src/globals.c
index 15fb089..61a9c97 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -830,6 +830,9 @@ void   *dkim_signatures         = NULL;
 uschar *dkim_signers             = NULL;
 uschar *dkim_signing_domain      = NULL;
 uschar *dkim_signing_selector    = NULL;
+uschar *dkim_verify_hashes       = US"sha256:sha512:sha1";
+uschar *dkim_verify_keytypes     = US"ed25519:rsa";
+BOOL    dkim_verify_minimal      = FALSE;
 uschar *dkim_verify_overall      = NULL;
 uschar *dkim_verify_signers      = US"$dkim_signers";
 uschar *dkim_verify_status     = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index c226004..4ab43ca 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -503,6 +503,9 @@ extern void   *dkim_signatures;           /* Actually a (pdkim_signature *) but mos
 extern uschar *dkim_signers;           /* Expansion variable, holds colon-separated list of domains and identities that have signed a message */
 extern uschar *dkim_signing_domain;    /* Expansion variable, domain used for signing a message. */
 extern uschar *dkim_signing_selector;  /* Expansion variable, selector used for signing a message. */
+extern uschar *dkim_verify_hashes;     /* Preference order for signatures */
+extern uschar *dkim_verify_keytypes;   /* Preference order for signatures */
+extern BOOL    dkim_verify_minimal;    /* Shortcircuit signture verification */
 extern uschar *dkim_verify_overall;    /* First successful domain verified, or null */
 extern uschar *dkim_verify_signers;    /* Colon-separated list of domains for each of which we call the DKIM ACL */
 extern uschar *dkim_verify_status;     /* result for this signature */
diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c
index f10f206..79e7c63 100644
--- a/src/src/pdkim/pdkim.c
+++ b/src/src/pdkim/pdkim.c
@@ -121,6 +121,14 @@ 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)
 {
@@ -561,9 +569,7 @@ 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)
@@ -1411,16 +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)
-  {
-  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);
@@ -1441,6 +1444,61 @@ 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,
@@ -1472,6 +1530,11 @@ have a hash to do for ARC. */

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");
@@ -1496,7 +1559,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
     }


   /*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)
@@ -1550,7 +1613,6 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
     /* 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);
@@ -1831,6 +1893,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next)
       {
       sig->verify_status = PDKIM_VERIFY_PASS;
       verify_pass = TRUE;
+      if (dkim_verify_minimal) break;
       }


NEXT_VERIFY:
diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h
index b2f586c..0c9d46d 100644
--- a/src/src/pdkim/pdkim.h
+++ b/src/src/pdkim/pdkim.h
@@ -74,9 +74,6 @@
/* Some parameter values */
#define PDKIM_QUERYMETHOD_DNS_TXT 0

-/*#define PDKIM_ALGO_RSA_SHA256     0 */
-/*#define PDKIM_ALGO_RSA_SHA1       1 */
-
 #define PDKIM_CANON_SIMPLE        0
 #define PDKIM_CANON_RELAXED       1


@@ -142,7 +139,7 @@ typedef struct pdkim_signature {
/* (v=) The version, as an integer. Currently, always "1" */
int version;

-  /* (a=) The signature algorithm. Either PDKIM_ALGO_RSA_SHA256 */
+  /* (a=) The signature algorithm. */
   int keytype;    /* pdkim_keytypes index */
   int hashtype;    /* pdkim_hashes index */


diff --git a/src/src/readconf.c b/src/src/readconf.c
index a5482f7..05d3077 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -117,6 +117,9 @@ static optionlist optionlist_config[] = {
 #endif
   { "disable_ipv6",             opt_bool,        &disable_ipv6 },
 #ifndef DISABLE_DKIM
+  { "dkim_verify_hashes",       opt_stringptr,   &dkim_verify_hashes },
+  { "dkim_verify_keytypes",     opt_stringptr,   &dkim_verify_keytypes },
+  { "dkim_verify_minimal",      opt_bool,        &dkim_verify_minimal },
   { "dkim_verify_signers",      opt_stringptr,   &dkim_verify_signers },
 #endif
 #ifdef EXPERIMENTAL_DMARC
diff --git a/test/confs/4509 b/test/confs/4509
new file mode 100644
index 0000000..5c64a49
--- /dev/null
+++ b/test/confs/4509
@@ -0,0 +1,28 @@
+# Exim test configuration 4509
+
+SERVER=
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+acl_smtp_data = check_data
+
+log_selector = +dkim_verbose
+
+# No sha1 !
+dkim_verify_hashes = sha256 : sha512
+
+queue_only
+queue_run_in_order
+
+
+begin acl
+
+check_data:
+  accept logwrite = ${authresults {$primary_hostname}}
+
+# End
diff --git a/test/confs/4520 b/test/confs/4520
index f345b91..1f31623 100644
--- a/test/confs/4520
+++ b/test/confs/4520
@@ -15,6 +15,9 @@ acl_smtp_dkim = accept logwrite = dkim_acl: signer: $dkim_cur_signer bits: $dkim
 acl_smtp_data = accept logwrite = data acl: dkim status $dkim_verify_status


dkim_verify_signers = $dkim_signers
+.ifdef FILTER
+dkim_verify_minimal = true
+.endif

DDIR=DIR/aux-fixed/dkim

diff --git a/test/confs/4541 b/test/confs/4541
new file mode 120000
index 0000000..072f5fa
--- /dev/null
+++ b/test/confs/4541
@@ -0,0 +1 @@
+4520
\ No newline at end of file
diff --git a/test/log/4509 b/test/log/4509
new file mode 100644
index 0000000..0ab1a76
--- /dev/null
+++ b/test/log/4509
@@ -0,0 +1,5 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 10HmaX-0005vi-00 Authentication-Results: myhost.test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@???
diff --git a/test/log/4541 b/test/log/4541
new file mode 100644
index 0000000..b8a5f33
--- /dev/null
+++ b/test/log/4541
@@ -0,0 +1,28 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss for a@???
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a@??? R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss for b@???
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => b@??? R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 rcpt acl: macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmaY-0005vi-00 dkim_acl: signer: test.ex bits: 512 h=From
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sed c=relaxed/relaxed a=ed25519-sha256 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 dkim_acl: signer: test.ex bits: 1024 h=From
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 data acl: dkim status pass:pass
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@??? H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@??? for a@???
+1999-03-02 09:44:33 10HmaY-0005vi-00 => a <a@???> R=server_store T=file
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 rcpt acl: macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmbA-0005vi-00 dkim_acl: signer: test.ex bits: 512 h=From
+1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=sed c=relaxed/relaxed a=ed25519-sha256 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmbA-0005vi-00 dkim_acl: signer: test.ex bits: 1024 h=From
+1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [not verified]
+1999-03-02 09:44:33 10HmbA-0005vi-00 data acl: dkim status pass:none
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@??? H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaZ-0005vi-00@??? for b@???
+1999-03-02 09:44:33 10HmbA-0005vi-00 => b <b@???> R=server_store T=file
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
diff --git a/test/mail/4541.a b/test/mail/4541.a
new file mode 100644
index 0000000..e1c95f0
--- /dev/null
+++ b/test/mail/4541.a
@@ -0,0 +1,26 @@
+From CALLER@??? Tue Mar 02 09:44:33 1999
+Received: from the.local.host.name ([ip4.ip4.ip4.ip4] helo=myhost.test.ex)
+    by myhost.test.ex with esmtp (Exim x.yz)
+    (envelope-from <CALLER@???>)
+    id 10HmaY-0005vi-00
+    for a@???; Tue, 2 Mar 1999 09:44:33 +0000
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
+    s=sel; h=From; bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=; b=toy5chxow6W
+    7Nn3qMvjZs+i0H00bQfi+6nakV6i36cRrZM/oWziHrc5IfYZuQunWNUA9UHnatK35Nsl7ZJRBU4em
+    wtzdO60jXnH7ZVyYjKxqTow9uCuuBKCgXdKxt1hpEfY0m7uUKt9OaqA0464NH5wEC4o/pt1aReidE
+    hvI6IY=;
+DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex
+    ; s=sed; h=From; bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=; b=IKNwoUbCe
+    ayHoA7j2L0IU1IFuapa3DrlNx9wPlBodM1iKJ57WGibKzefQNdTjymHPsMlQ9fS+h9ZSsHmVNBdDA
+    ==;
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+    (envelope-from <CALLER@???>)
+    id 10HmaX-0005vi-00
+    for a@???; Tue, 2 Mar 1999 09:44:33 +0000
+From: nobody@???
+Message-Id: <E10HmaX-0005vi-00@???>
+Sender: CALLER_NAME <CALLER@???>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+content
+
diff --git a/test/mail/4541.b b/test/mail/4541.b
new file mode 100644
index 0000000..7927bbc
--- /dev/null
+++ b/test/mail/4541.b
@@ -0,0 +1,26 @@
+From CALLER@??? Tue Mar 02 09:44:33 1999
+Received: from the.local.host.name ([ip4.ip4.ip4.ip4] helo=myhost.test.ex)
+    by myhost.test.ex with esmtp (Exim x.yz)
+    (envelope-from <CALLER@???>)
+    id 10HmbA-0005vi-00
+    for b@???; Tue, 2 Mar 1999 09:44:33 +0000
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
+    s=sel; h=From; bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=; b=toy5chxow6W
+    7Nn3qMvjZs+i0H00bQfi+6nakV6i36cRrZM/oWziHrc5IfYZuQunWNUA9UHnatK35Nsl7ZJRBU4em
+    wtzdO60jXnH7ZVyYjKxqTow9uCuuBKCgXdKxt1hpEfY0m7uUKt9OaqA0464NH5wEC4o/pt1aReidE
+    hvI6IY=;
+DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex
+    ; s=sed; h=From; bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=; b=IKNwoUbCe
+    ayHoA7j2L0IU1IFuapa3DrlNx9wPlBodM1iKJ57WGibKzefQNdTjymHPsMlQ9fS+h9ZSsHmVNBdDA
+    ==;
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+    (envelope-from <CALLER@???>)
+    id 10HmaZ-0005vi-00
+    for b@???; Tue, 2 Mar 1999 09:44:33 +0000
+From: nobody@???
+Message-Id: <E10HmaZ-0005vi-00@???>
+Sender: CALLER_NAME <CALLER@???>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+content
+
diff --git a/test/scripts/4500-DKIM/4509 b/test/scripts/4500-DKIM/4509
new file mode 100644
index 0000000..c450d65
--- /dev/null
+++ b/test/scripts/4500-DKIM/4509
@@ -0,0 +1,41 @@
+# DKIM verify, dkim_verify_hashes option
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# This should not ve verified, as the config ignores the sha1 sig
+#  - sha1, 1024b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --method=simple/simple < aux-fixed/4500.msg1.txt
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@???>
+??? 250
+RCPT TO:<a@???>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+    :date:message-id:subject; s=sel; bh=OB9dZVu7+5/ufs3TH9leIcEpXSo=; b=
+    PeUA8iBGfStWv+9/BBKkvCEYj/AVMl4e9k+AqWOXKyuEUfHxqAnV+sPnOejpmvT8
+    41kuM4u0bICvK371YvB/yO61vtliRhyqU76Y2e55p2uvMADb3UyDhLyzpco4+yBo
+    1w0AuIxu0VU4TK8UmOLyCw/1hxrh1DcEInbEMEKJ7kI=
+From: mrgus@???
+To: bakawolf@???
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@???>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+killdaemon
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/4540-DKIM-Ed25519/4541 b/test/scripts/4540-DKIM-Ed25519/4541
new file mode 100644
index 0000000..cec41df
--- /dev/null
+++ b/test/scripts/4540-DKIM-Ed25519/4541
@@ -0,0 +1,30 @@
+# DKIM verify, multiple and dkim_verify_minimal
+# This relies on multiple-signing working (4545 tests that)
+#
+# Verify both
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+exim -DSELECTOR=sel:sed -DOPT=From: -odf a@???
+From: nobody@???
+
+content
+****
+#
+millisleep 500
+killdaemon
+#
+#
+# Verify only EC sig
+exim -bd -DSERVER=server -DFILTER=y -oX PORT_D
+****
+#
+exim -DSELECTOR=sel:sed -DOPT=From: -odf b@???
+From: nobody@???
+
+content
+****
+#
+millisleep 500
+killdaemon
+no_msglog_check