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_identity smtp string&!! unset
 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.
 
+.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".
@@ -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.
 
-.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"
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.
-    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.
index ea2007225e07c17a12163fdf2f5712e81f6d7e81..cd8a16ae61b8cd04f96143d4325a6a097bd3bda1 100644 (file)
@@ -471,18 +471,15 @@ int sread;
 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)))
-  {
   /* 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. */
 
@@ -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)))
-    {
-    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)))
@@ -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_identity_expanded = NULL;
 
     /* 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;
@@ -548,23 +537,15 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
       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)))
-      {
-      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
@@ -607,11 +588,13 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
       }
 
     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. */
@@ -627,7 +610,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
 
     pdkim_set_optional(sig,
                        CS dkim_sign_headers_expanded,
-                       NULL,
+                       dkim_identity_expanded,
                        pdkim_canon,
                        pdkim_canon, -1, 0, 0);
 
@@ -694,6 +677,11 @@ pk_bad:
 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
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;
+  uschar *dkim_identity;
   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) },
+  { "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,
@@ -278,10 +280,11 @@ smtp_transport_options_block smtp_transport_option_defaults = {
 #ifndef DISABLE_DKIM
  .dkim =
    {.dkim_domain =             NULL,
+    .dkim_identity =           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},
index 5f46498467015c8df8267d53faa90d199e2eea2c..897c1a6756baef9f8a468ee518ebd721c0c4e274 100644 (file)
@@ -50,6 +50,8 @@ send_to_server:
 
 .ifndef HEADERS_MAXSIZE
   dkim_sign_headers =  OPT
+.else
+  dkim_identity =      allheaders@$dkim_domain
 .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 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: 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
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
-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: 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