DKIM: support specifying alternate-identity tag for signing. Bug 2170
authorJeremy Harris <jgh146exb@wizmail.org>
Mon, 25 Sep 2017 15:36:47 +0000 (16:36 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 25 Sep 2017 15:36:47 +0000 (16:36 +0100)
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/dkim.c
src/src/structs.h
src/src/transports/smtp.c
test/confs/4520
test/log/4520
test/log/4523

index 44a274b98f641b644753b752c41f3e4564a52a35..4a8e1d06e39b4f5945d6e23bd634c13984fd729f 100644 (file)
@@ -23800,6 +23800,7 @@ of the message. Its value must not be zero. See also &%final_timeout%&.
 .option dkim_strict smtp string&!! unset
 .option dkim_sign_headers smtp string&!! unset
 .option dkim_hash smtp string&!! sha256
 .option dkim_strict smtp string&!! unset
 .option dkim_sign_headers smtp string&!! unset
 .option dkim_hash smtp string&!! sha256
+.option dkim_identity smtp string&!! unset
 DKIM signing options.  For details see section &<<SECDKIMSIGN>>&.
 
 
 DKIM signing options.  For details see section &<<SECDKIMSIGN>>&.
 
 
@@ -38553,6 +38554,19 @@ is set.
 .endlist
 If the option is empty after expansion, DKIM signing is not done.
 
 .endlist
 If the option is empty after expansion, DKIM signing is not done.
 
+.new
+.option dkim_hash smtp string&!! sha256
+Can be set alternatively to &"sha1"& to use an alternate hash
+method.  Note that sha1 is now condidered insecure, and deprecated.
+
+.option dkim_identity smtp string&!! unset
+If set after expansion, the value is used to set an "i=" tag in
+the signing header.  The DKIM standards restrict the permissible
+syntax of this optional tag to a mail address, with possibly-empty
+local part, an @, and a domain identical to or subdomain of the "d="
+tag value.  Note that Exim does not check the value.
+.wen
+
 .option dkim_canon smtp string&!! unset
 This option sets the canonicalization method used when signing a message.
 The DKIM RFC currently supports two methods: "simple" and "relaxed".
 .option dkim_canon smtp string&!! unset
 This option sets the canonicalization method used when signing a message.
 The DKIM RFC currently supports two methods: "simple" and "relaxed".
@@ -38572,12 +38586,6 @@ list of header names. Headers with these names will be included in the message
 signature.
 When unspecified, the header names recommended in RFC4871 will be used.
 
 signature.
 When unspecified, the header names recommended in RFC4871 will be used.
 
-.new
-.option dkim_hash smtp string&!! sha256
-Can be set alternatively to &"sha1"& to use an alternate hash
-method.  Note that sha1 is now condidered insecure, and deprecated.
-.wen
-
 
 .section "Verifying DKIM signatures in incoming mail" "SECID514"
 .cindex "DKIM" "verification"
 
 .section "Verifying DKIM signatures in incoming mail" "SECID514"
 .cindex "DKIM" "verification"
index 88def26299dca6d48c88f6cac9007ecbca28ac72..39fce1eab71e533a9592a8225ac984b7a4a0a34d 100644 (file)
@@ -52,7 +52,7 @@ Version 4.90
     is opened with a TFO cookie.
 
 13. DKIM support for multiple signing, by domain and/or key-selector.
     is opened with a TFO cookie.
 
 13. DKIM support for multiple signing, by domain and/or key-selector.
-    DKIM support for multiple hashes.
+    DKIM support for multiple hashes, and for alternate-identity tags.
 
 14. Exipick understands -C|--config for an alternative Exim
     configuration file.
 
 14. Exipick understands -C|--config for an alternative Exim
     configuration file.
index ea2007225e07c17a12163fdf2f5712e81f6d7e81..cd8a16ae61b8cd04f96143d4325a6a097bd3bda1 100644 (file)
@@ -471,18 +471,15 @@ int sread;
 uschar buf[4096];
 int save_errno = 0;
 int old_pool = store_pool;
 uschar buf[4096];
 int save_errno = 0;
 int old_pool = store_pool;
+uschar * errwhen;
 
 store_pool = POOL_MAIN;
 
 pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
 
 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
 
 store_pool = POOL_MAIN;
 
 pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
 
 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
-  {
   /* expansion error, do not send message. */
   /* expansion error, do not send message. */
-  log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-            "dkim_domain: %s", expand_string_message);
-  goto bad;
-  }
+  { errwhen = US"dkim_domain"; goto expand_bad; }
 
 /* Set $dkim_domain expansion variable to each unique domain in list. */
 
 
 /* Set $dkim_domain expansion variable to each unique domain in list. */
 
@@ -509,11 +506,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
 
   if (!(dkim_sel = expand_string(dkim->dkim_selector)))
   if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
 
   if (!(dkim_sel = expand_string(dkim->dkim_selector)))
   if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
-    {
-    log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-              "dkim_selector: %s", expand_string_message);
-    goto bad;
-    }
+    { errwhen = US"dkim_selector"; goto expand_bad; }
 
   while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
          NULL, 0)))
 
   while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
          NULL, 0)))
@@ -523,18 +516,14 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
     uschar * dkim_sign_headers_expanded = NULL;
     uschar * dkim_private_key_expanded;
     uschar * dkim_hash_expanded;
     uschar * dkim_sign_headers_expanded = NULL;
     uschar * dkim_private_key_expanded;
     uschar * dkim_hash_expanded;
+    uschar * dkim_identity_expanded = NULL;
 
     /* Get canonicalization to use */
 
     dkim_canon_expanded = dkim->dkim_canon
       ? expand_string(dkim->dkim_canon) : US"relaxed";
 
     /* Get canonicalization to use */
 
     dkim_canon_expanded = dkim->dkim_canon
       ? expand_string(dkim->dkim_canon) : US"relaxed";
-    if (!dkim_canon_expanded)
-      {
-      /* expansion error, do not send message. */
-      log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-                "dkim_canon: %s", expand_string_message);
-      goto bad;
-      }
+    if (!dkim_canon_expanded)  /* expansion error, do not send message. */
+      { errwhen = US"dkim_canon"; goto expand_bad; }
 
     if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
       pdkim_canon = PDKIM_CANON_RELAXED;
 
     if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
       pdkim_canon = PDKIM_CANON_RELAXED;
@@ -548,23 +537,15 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
       pdkim_canon = PDKIM_CANON_RELAXED;
       }
 
       pdkim_canon = PDKIM_CANON_RELAXED;
       }
 
-    if (dkim->dkim_sign_headers)
-      if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
-       {
-       log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-                  "dkim_sign_headers: %s", expand_string_message);
-       goto bad;
-       }
-                         /* else pass NULL, which means default header list */
+    if (  dkim->dkim_sign_headers
+       && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
+      { errwhen = US"dkim_sign_header"; goto expand_bad; }
+    /* else pass NULL, which means default header list */
 
     /* Get private key to use. */
 
     if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
 
     /* Get private key to use. */
 
     if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
-      {
-      log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-                "dkim_private_key: %s", expand_string_message);
-      goto bad;
-      }
+      { errwhen = US"dkim_private_key"; goto expand_bad; }
 
     if (  Ustrlen(dkim_private_key_expanded) == 0
        || Ustrcmp(dkim_private_key_expanded, "0") == 0
 
     if (  Ustrlen(dkim_private_key_expanded) == 0
        || Ustrcmp(dkim_private_key_expanded, "0") == 0
@@ -607,11 +588,13 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
       }
 
     if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
       }
 
     if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
-      {
-      log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-                "dkim_hash: %s", expand_string_message);
-      goto bad;
-      }
+      { errwhen = US"dkim_hash"; goto expand_bad; }
+
+    if (dkim->dkim_identity)
+      if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
+       { errwhen = US"dkim_identity"; goto expand_bad; }
+      else if (!*dkim_identity_expanded)
+       dkim_identity_expanded = NULL;
 
   /*XXX so we currently nail signing to RSA + this hash.
   Need to extract algo from privkey and check for disallowed combos. */
 
   /*XXX so we currently nail signing to RSA + this hash.
   Need to extract algo from privkey and check for disallowed combos. */
@@ -627,7 +610,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
 
     pdkim_set_optional(sig,
                        CS dkim_sign_headers_expanded,
 
     pdkim_set_optional(sig,
                        CS dkim_sign_headers_expanded,
-                       NULL,
+                       dkim_identity_expanded,
                        pdkim_canon,
                        pdkim_canon, -1, 0, 0);
 
                        pdkim_canon,
                        pdkim_canon, -1, 0, 0);
 
@@ -694,6 +677,11 @@ pk_bad:
 bad:
   sigbuf = NULL;
   goto CLEANUP;
 bad:
   sigbuf = NULL;
   goto CLEANUP;
+
+expand_bad:
+  log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
+             errwhen, expand_string_message);
+  goto bad;
 }
 
 #endif
 }
 
 #endif
index 06fcd4188fcb4225cdaa6e6b1837c895fad91985..d8ac19ab8c8eaf3671a88f082da0ddb6b2f1424f 100644 (file)
@@ -867,6 +867,7 @@ typedef BOOL (*oicf) (uschar *message_id, void *data);
 /* DKIM information for transport */
 struct ob_dkim {
   uschar *dkim_domain;
 /* DKIM information for transport */
 struct ob_dkim {
   uschar *dkim_domain;
+  uschar *dkim_identity;
   uschar *dkim_private_key;
   uschar *dkim_selector;
   uschar *dkim_canon;
   uschar *dkim_private_key;
   uschar *dkim_selector;
   uschar *dkim_canon;
index 557d650ae3d97b29d0fddea568944dc1244febd8..461b26c4a2b3817692bad84a99ec088b9520a731 100644 (file)
@@ -45,6 +45,8 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_domain) },
   { "dkim_hash", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_hash) },
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_domain) },
   { "dkim_hash", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_hash) },
+  { "dkim_identity", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim.dkim_identity) },
   { "dkim_private_key", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_private_key) },
   { "dkim_selector", opt_stringptr,
   { "dkim_private_key", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_private_key) },
   { "dkim_selector", opt_stringptr,
@@ -278,10 +280,11 @@ smtp_transport_options_block smtp_transport_option_defaults = {
 #ifndef DISABLE_DKIM
  .dkim =
    {.dkim_domain =             NULL,
 #ifndef DISABLE_DKIM
  .dkim =
    {.dkim_domain =             NULL,
+    .dkim_identity =           NULL,
     .dkim_private_key =                NULL,
     .dkim_selector =           NULL,
     .dkim_canon =              NULL,
     .dkim_private_key =                NULL,
     .dkim_selector =           NULL,
     .dkim_canon =              NULL,
-    .dkim_sign_headers =        NULL,
+    .dkim_sign_headers =       NULL,
     .dkim_strict =             NULL,
     .dkim_hash =               US"sha256",
     .dot_stuffed =             FALSE},
     .dkim_strict =             NULL,
     .dkim_hash =               US"sha256",
     .dot_stuffed =             FALSE},
index 5f46498467015c8df8267d53faa90d199e2eea2c..897c1a6756baef9f8a468ee518ebd721c0c4e274 100644 (file)
@@ -50,6 +50,8 @@ send_to_server:
 
 .ifndef HEADERS_MAXSIZE
   dkim_sign_headers =  OPT
 
 .ifndef HEADERS_MAXSIZE
   dkim_sign_headers =  OPT
+.else
+  dkim_identity =      allheaders@$dkim_domain
 .endif
 .ifdef VALUE
   dkim_hash =          VALUE
 .endif
 .ifdef VALUE
   dkim_hash =          VALUE
index 73854cfc139ab471257a6ea49f265666aef6072b..8daa636c025f8fdedfd8f88b509c83ca72848daa 100644 (file)
@@ -23,8 +23,9 @@
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <b@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <b@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 i=allheaders@test.ex [verification succeeded]
 1999-03-02 09:44:33 10HmbC-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject: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 10HmbC-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject: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 10HmbC-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject: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 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbB-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <c@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbB-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <c@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
index 45eb89c9c57e7bc24ddb0b231aeb243a720cf648..d1e5ebba3c8e6a6c7377bcaa0519e4863d50241a 100644 (file)
@@ -4,8 +4,9 @@
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 i=allheaders@test.ex [verification succeeded]
 1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject: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 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject: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 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject: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 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed