DKIM: support timestamp and expiry tags in signing. Bug 2260
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 9 Jun 2018 20:39:44 +0000 (21:39 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 9 Jun 2018 21:17:54 +0000 (22:17 +0100)
doc/doc-docbook/spec.xfpt
doc/doc-txt/OptionLists.txt
src/src/dkim.c
src/src/structs.h
src/src/transports/smtp.c
test/confs/4520
test/log/4520
test/mail/4520.b
test/runtest
test/scripts/4500-DKIM/4520

index 431d4560c1129a2cba642c35e780c2fbb4d2eb25..863a6b949f9bc820cbb9e126af0c308665eff4d6 100644 (file)
@@ -23976,14 +23976,15 @@ the message. As a result, the overall timeout for a message depends on the size
 of the message. Its value must not be zero. See also &%final_timeout%&.
 
 
 of the message. Its value must not be zero. See also &%final_timeout%&.
 
 
+.option dkim_canon smtp string&!! unset
 .option dkim_domain smtp string list&!! unset
 .option dkim_domain smtp string list&!! unset
-.option dkim_selector smtp string&!! unset
+.option dkim_hash smtp string&!! sha256
+.option dkim_identity smtp string&!! unset
 .option dkim_private_key smtp string&!! unset
 .option dkim_private_key smtp string&!! unset
-.option dkim_canon smtp string&!! unset
+.option dkim_selector smtp string&!! unset
 .option dkim_strict smtp string&!! unset
 .option dkim_sign_headers smtp string&!! "per RFC"
 .option dkim_strict smtp string&!! unset
 .option dkim_sign_headers smtp string&!! "per RFC"
-.option dkim_hash smtp string&!! sha256
-.option dkim_identity smtp string&!! unset
+.option dkim_timestamps smtp string&!! unset
 DKIM signing options.  For details see section &<<SECDKIMSIGN>>&.
 
 
 DKIM signing options.  For details see section &<<SECDKIMSIGN>>&.
 
 
@@ -39102,6 +39103,18 @@ If a '+' prefix if used, all headers that are present with this name
 will be signed, and one signature added for a missing header with the
 name will be appended.
 
 will be signed, and one signature added for a missing header with the
 name will be appended.
 
+.new
+.option dkim_timestamps smtp integer&!! unset
+This option controls the inclusion of timestamp information in the signature.
+If not set, no such information will be included.
+Otherwise, must be an unsigned number giving an offset in seconds from the current time
+for the expiry tag
+(eg. 1209600 for two weeks);
+both creation (t=) and expiry (x=) tags will be included.
+
+RFC 6376 lists these tags as RECOMMENDED.
+.wen
+
 
 .section "Verifying DKIM signatures in incoming mail" "SECDKIMVFY"
 .cindex "DKIM" "verification"
 
 .section "Verifying DKIM signatures in incoming mail" "SECDKIMVFY"
 .cindex "DKIM" "verification"
index 91ce182fd6fcc9b363d4416404e6cff5e9cfab17..0a6a32073434147c4906a40141a432a2c4ac4d64 100644 (file)
@@ -169,6 +169,7 @@ dkim_private_key                     string*         unset         smtp
 dkim_selector                        string*         unset         smtp              4.70
 dkim_sign_headers                    string*         (RFC4871)     smtp              4.70
 dkim_strict                          string*         unset         smtp              4.70
 dkim_selector                        string*         unset         smtp              4.70
 dkim_sign_headers                    string*         (RFC4871)     smtp              4.70
 dkim_strict                          string*         unset         smtp              4.70
+dkim_timestamps                      integer*        unset         smtp              4.92
 dkim_verify_signers                  string*         $dkim_signers main              4.70
 directory                            string*         unset         appendfile
 directory_file                       string*         +             appendfile
 dkim_verify_signers                  string*         $dkim_signers main              4.70
 directory                            string*         unset         appendfile
 directory_file                       string*         +             appendfile
index 317f6e50dd2460551386528998f9c613e81f8cf9..edbeded5e4ac886885d37847e9f9b12219f2d568 100644 (file)
@@ -645,6 +645,8 @@ if (dkim_domain)
     uschar * dkim_private_key_expanded;
     uschar * dkim_hash_expanded;
     uschar * dkim_identity_expanded = NULL;
     uschar * dkim_private_key_expanded;
     uschar * dkim_hash_expanded;
     uschar * dkim_identity_expanded = NULL;
+    uschar * dkim_timestamps_expanded = NULL;
+    unsigned long tval = 0, xval = 0;
 
     /* Get canonicalization to use */
 
 
     /* Get canonicalization to use */
 
@@ -695,6 +697,13 @@ if (dkim_domain)
       else if (!*dkim_identity_expanded)
        dkim_identity_expanded = NULL;
 
       else if (!*dkim_identity_expanded)
        dkim_identity_expanded = NULL;
 
+    if (dkim->dkim_timestamps)
+      if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
+       { errwhen = US"dkim_timestamps"; goto expand_bad; }
+      else
+       xval = (tval = (unsigned long) time(NULL))
+             + strtoul(dkim_timestamps_expanded, NULL, 10);
+
     if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
                          dkim_signing_selector,
                          dkim_private_key_expanded,
     if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
                          dkim_signing_selector,
                          dkim_private_key_expanded,
@@ -708,7 +717,7 @@ if (dkim_domain)
                        CS dkim_sign_headers_expanded,
                        CS dkim_identity_expanded,
                        pdkim_canon,
                        CS dkim_sign_headers_expanded,
                        CS dkim_identity_expanded,
                        pdkim_canon,
-                       pdkim_canon, -1, 0, 0);
+                       pdkim_canon, -1, tval, xval);
 
     if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
       goto bad;
 
     if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
       goto bad;
index 98c95010d2cf238ec51dc69fe4e292a132436ae5..8384920ee16f16b94329f753276aecf8e687f5b7 100644 (file)
@@ -878,6 +878,7 @@ struct ob_dkim {
   uschar *dkim_sign_headers;
   uschar *dkim_strict;
   uschar *dkim_hash;
   uschar *dkim_sign_headers;
   uschar *dkim_strict;
   uschar *dkim_hash;
+  uschar *dkim_timestamps;
   BOOL    dot_stuffed;
   BOOL    force_bodyhash;
 #ifdef EXPERIMENTAL_ARC
   BOOL    dot_stuffed;
   BOOL    force_bodyhash;
 #ifdef EXPERIMENTAL_ARC
index 2dfb5b73af4ad31e9f192db1d82d648207f70100..6d7085881d76c88fe8d6fb681ebaf5f1f7da0130 100644 (file)
@@ -63,6 +63,8 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_sign_headers) },
   { "dkim_strict", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_strict) },
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_sign_headers) },
   { "dkim_strict", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_strict) },
+  { "dkim_timestamps", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim.dkim_timestamps) },
 #endif
   { "dns_qualify_single",   opt_bool,
       (void *)offsetof(smtp_transport_options_block, dns_qualify_single) },
 #endif
   { "dns_qualify_single",   opt_bool,
       (void *)offsetof(smtp_transport_options_block, dns_qualify_single) },
@@ -295,6 +297,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
     .dkim_sign_headers =       NULL,
     .dkim_strict =             NULL,
     .dkim_hash =               US"sha256",
     .dkim_sign_headers =       NULL,
     .dkim_strict =             NULL,
     .dkim_hash =               US"sha256",
+    .dkim_timestamps =         NULL,
     .dot_stuffed =             FALSE,
     .force_bodyhash =          FALSE,
 # ifdef EXPERIMENTAL_ARC
     .dot_stuffed =             FALSE,
     .force_bodyhash =          FALSE,
 # ifdef EXPERIMENTAL_ARC
index 3b8d781eae3fe3c9cabbccd3e88a9492bd8ec941..89769230f9ed458bf49b249cc869697b32e271cf 100644 (file)
@@ -67,6 +67,9 @@ send_to_server:
 .ifdef STRICT
   dkim_strict =                STRICT
 .endif
 .ifdef STRICT
   dkim_strict =                STRICT
 .endif
+.ifdef TIMES
+  dkim_timestamps =    TIMES
+.endif
 
 file:
   driver =     appendfile
 
 file:
   driver =     appendfile
index 2208b4f7290e8c13c5caeee29b7b375b4c2c8feb..d583933102e5d693a3256918cb554ba012d5b007 100644 (file)
@@ -34,7 +34,7 @@
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 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: 1024 h=From:From
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 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: 1024 h=From:From
-1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 t=T x=T+10 [verification succeeded]
 1999-03-02 09:44:33 10HmbA-0005vi-00 data acl: dkim status pass
 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 => b <b@test.ex> R=server_store T=file
 1999-03-02 09:44:33 10HmbA-0005vi-00 data acl: dkim status pass
 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 => b <b@test.ex> R=server_store T=file
index 14ef0ddf608778b9a5d55795f09e7e10ddda2a60..22b8c62ed07162af3627656d9df04a9efdc60392 100644 (file)
@@ -5,10 +5,8 @@ Received: from the.local.host.name ([ip4.ip4.ip4.ip4] helo=myhost.test.ex)
        id 10HmbA-0005vi-00
        for b@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
        id 10HmbA-0005vi-00
        for b@test.ex; 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:From; bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=; b=n8PsoE
-       fI7/q6r3UBtnd9bOynzqROT5SwDn/vctQeEYk79CsvhPmpFED/kb7+ojla6+ITBgvyRQMnBMxJwmk
-       RjvQsvnJD7z/kyB0xJJzWPvcwS8TTJZ0oBUEUJyDmRSzDDTyOGgTWLpxD7QLoWi8WS49/tWUGkub2
-       hiGw06hIjc4=;
+       s=sel; h=From:From; bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;
+       t=T; x=T+10; b=bbbb;
 Received: from CALLER by myhost.test.ex with local (Exim x.yz)
        (envelope-from <CALLER@myhost.test.ex>)
        id 10HmaZ-0005vi-00
 Received: from CALLER by myhost.test.ex with local (Exim x.yz)
        (envelope-from <CALLER@myhost.test.ex>)
        id 10HmaZ-0005vi-00
index 63e6e11ea8f2aa5ab0af7dc5ecacce4474524720..0dc3cca739fc91a9974d74f07aa9858ac7d50c57 100755 (executable)
@@ -1210,6 +1210,21 @@ RESET_AFTER_EXTRA_LINE_READ:
     s/(TLS error on connection [^:]*: error:)[0-9A-F]{8}(:system library):(?:fopen|func\(4095\)):(No such file or directory)$/$1xxxxxxxx$2:fopen:$3/;
     s/(DANE attempt failed.*error:)[0-9A-F]{8}(:SSL routines:)(ssl3_get_server_certificate|tls_process_server_certificate|CONNECT_CR_CERT)(?=:certificate verify failed$)/$1xxxxxxxx$2ssl3_get_server_certificate/;
     s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./;
     s/(TLS error on connection [^:]*: error:)[0-9A-F]{8}(:system library):(?:fopen|func\(4095\)):(No such file or directory)$/$1xxxxxxxx$2:fopen:$3/;
     s/(DANE attempt failed.*error:)[0-9A-F]{8}(:SSL routines:)(ssl3_get_server_certificate|tls_process_server_certificate|CONNECT_CR_CERT)(?=:certificate verify failed$)/$1xxxxxxxx$2ssl3_get_server_certificate/;
     s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./;
+
+    # DKIM timestamps
+    s/(DKIM: d=.*) t=([0-9]*) x=([0-9]*)(?{ return $3 - $2; }) /$1 t=T x=T+$^R /;
+    }
+
+  # ======== mail ========
+
+  elsif ($is_mail)
+    {
+    # DKIM timestamps
+    if ( /^\s+t=[0-9]*; x=[0-9]*; b=[A-Za-z0-9+\/]+$/ ) {
+      s/^(\s+)t=([0-9]*); x=([0-9]*);(?{ return $3 - $2; }) b=[A-Za-z0-9+\/]+$/$1t=T; x=T+$^R; b=bbbb;/;
+      <IN>;
+      <IN>;
+      }
     }
 
   # ======== All files other than stderr ========
     }
 
   # ======== All files other than stderr ========
@@ -1569,7 +1584,7 @@ $munges =
 
     'optional_config' =>
     { 'stdout' => '/^(
 
     'optional_config' =>
     { 'stdout' => '/^(
-                  dkim_(canon|domain|private_key|selector|sign_headers|strict|hash|identity)
+                  dkim_(canon|domain|private_key|selector|sign_headers|strict|hash|identity|timestamps)
                   |gnutls_require_(kx|mac|protocols)
                   |hosts_(requ(est|ire)|try)_(dane|ocsp)
                  |dane_require_tls_ciphers
                   |gnutls_require_(kx|mac|protocols)
                   |hosts_(requ(est|ire)|try)_(dane|ocsp)
                  |dane_require_tls_ciphers
index f7fafb3e4bc03a8f28e7d4f5ae849d725fe613cf..8e60f4bec0ebe398a0eb2d44e483329170033ac2 100644 (file)
@@ -11,8 +11,8 @@ From: second@example.com
 content
 ****
 #
 content
 ****
 #
-# single header, oversigned
-exim -DOPT=From:From -odf b@test.ex
+# single header, oversigned, with timestamps
+exim -DOPT=From:From -DTIMES=10 -odf b@test.ex
 From: nobody@example.com
 
 content
 From: nobody@example.com
 
 content