Fix DKIM information leakage
authorJeremy Harris <jgh@wizmail.org>
Fri, 16 Dec 2016 20:45:44 +0000 (20:45 +0000)
committerJeremy Harris <jgh@wizmail.org>
Sun, 18 Dec 2016 14:02:28 +0000 (14:02 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/dkim.c
src/src/transports/smtp.c
test/confs/4510 [new file with mode: 0644]
test/log/4510 [new file with mode: 0644]
test/mail/4510.store [new file with mode: 0644]
test/runtest
test/scripts/4510-DKIM-Bounces/4510 [new file with mode: 0644]
test/scripts/4510-DKIM-Bounces/REQUIRES [new file with mode: 0644]

index 0598eccc8fb093a2c528ad8768ca4876958dd6b8..5324be398358c333fe7506e5ba1cb80d634ce856 100644 (file)
@@ -38273,6 +38273,7 @@ These options take (expandable) strings as arguments.
 MANDATORY:
 The domain you want to sign with. The result of this expanded
 option is put into the &%$dkim_domain%& expansion variable.
+If it is empty after expansion, DKIM signing is not done.
 
 .option dkim_selector smtp string&!! unset
 MANDATORY:
index 156413fcdd89e748c137799720bd9982fd661708..926a36dc1647a35a2f7cc2b3b327485fc4722187 100644 (file)
@@ -143,6 +143,10 @@ HS/02 Bug 1802: Do not half-close the connection after sending a request
 HS/03 Use "auto" as the default EC curve parameter. For OpenSSL < 1.0.2
       fallback to "prime256v1".
 
+JH/34 SECURITY: Use proper copy of DATA command in error message.
+      Could leak key material.  Remotely explaoitable.  CVE-2016-9963.
+
+
 Exim version 4.87
 -----------------
 JH/01 Bug 1664: Disable OCSP for GnuTLS library versions at/before 3.3.16
index 3fa11c80075b8a23b4d25892fe5f5045b807b31c..70c9547ece2e8715f4e625e7efd7cec4fcbeed1d 100644 (file)
@@ -612,6 +612,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
                         CS dkim_private_key_expanded,
                         PDKIM_ALGO_RSA_SHA256,
                         dkim->dot_stuffed);
+  dkim_private_key_expanded[0] = '\0';
   pdkim_set_optional(ctx,
                      CS dkim_sign_headers_expanded,
                      NULL,
index d6ef34eff09d875678c5efcf26d54f0ac97485cb..a19e85ffbbb26561488118e4b084837523649d63 100644 (file)
@@ -285,10 +285,11 @@ static uschar *rf_names[] = { US"NEVER", US"SUCCESS", US"FAILURE", US"DELAY" };
 
 /* Local statics */
 
-static uschar *smtp_command;   /* Points to last cmd for error messages */
-static uschar *mail_command;   /* Points to MAIL cmd for error messages */
-static BOOL    update_waiting; /* TRUE to update the "wait" database */
-static BOOL    pipelining_active; /* current transaction is in pipe mode */
+static uschar *smtp_command;           /* Points to last cmd for error messages */
+static uschar *mail_command;           /* Points to MAIL cmd for error messages */
+static uschar *data_command = US"";    /* Points to DATA cmd for error messages */
+static BOOL    update_waiting;         /* TRUE to update the "wait" database */
+static BOOL    pipelining_active;      /* current transaction is in pipe mode */
 
 
 /*************************************************
@@ -1390,10 +1391,14 @@ uschar * buffer = tctx->buffer;
 /* Write SMTP chunk header command */
 
 if (chunk_size > 0)
+  {
   if((cmd_count = smtp_write_command(tctx->outblock, FALSE, "BDAT %u%s\r\n",
                              chunk_size,
                              flags & tc_chunk_last ? " LAST" : "")
      ) < 0) return ERROR;
+  if (flags & tc_chunk_last)
+    data_command = string_copy(big_buffer);  /* Save for later error message */
+  }
 
 prev_cmd_count = cmd_count += tctx->cmd_count;
 
@@ -2512,6 +2517,7 @@ if (  !(peer_offered & PEER_OFFERED_CHUNKING)
     default: goto RESPONSE_FAILED;       /* I/O error, or any MAIL/DATA error */
     }
   pipelining_active = FALSE;
+  data_command = string_copy(big_buffer);  /* Save for later error message */
   }
 
 /* If there were no good recipients (but otherwise there have been no
@@ -2735,7 +2741,7 @@ else
 #else
            "LMTP error after %s: %s",
 #endif
-            big_buffer, string_printing(buffer));
+            data_command, string_printing(buffer));
           setflag(addr, af_pass_message);   /* Allow message to go to user */
           if (buffer[0] == '5')
             addr->transport_return = FAIL;
diff --git a/test/confs/4510 b/test/confs/4510
new file mode 100644 (file)
index 0000000..42c58aa
--- /dev/null
@@ -0,0 +1,57 @@
+# Exim test configuration 4510
+
+SERVER=
+OPT=
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+acl_smtp_dkim = accept logwrite = signer: $dkim_cur_signer bits: $dkim_key_length h=$dkim_headernames
+acl_smtp_data_prdr = accept local_parts = okuser
+
+prdr_enable
+
+# ----- Routers
+
+begin routers
+
+client:
+  driver = accept
+  condition = ${if eq {SERVER}{server}{no}{yes}}
+  transport = send_to_server
+
+server_dump:
+  driver = redirect
+  senders = ! :
+  data = :blackhole:
+
+server_store:
+  driver = accept
+  transport = store
+
+# ----- Transports
+
+begin transports
+
+store:
+  driver = appendfile
+  file = DIR/test-mail/store
+  return_path_add
+  user = CALLER
+
+send_to_server:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+
+  dkim_domain =                ${if def:sender_address_local_part {test.ex}}
+  dkim_selector =      sel
+  dkim_private_key =   DIR/aux-fixed/dkim/dkim.private
+  dkim_sign_headers =  From
+
+# End
diff --git a/test/log/4510 b/test/log/4510
new file mode 100644 (file)
index 0000000..0d826ab
--- /dev/null
@@ -0,0 +1,20 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 ** baduser@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4]: PRDR error after DATA: 550 PRDR R=<baduser@test.ex> refusal
+1999-03-02 09:44:33 10HmaX-0005vi-00 => okuser@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] PRDR C="250 PRDR R=<okuser@test.ex> acceptance"
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER@myhost.test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaZ-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaX-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 1225
+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 signer: test.ex bits: 1024 h=From
+1999-03-02 09:44:33 10HmbA-0005vi-00 PRDR R=<baduser@test.ex> refusal
+1999-03-02 09:44:33 10HmbA-0005vi-00 PRDR R=<okuser@test.ex> acceptance
+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 PRDR S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <okuser@test.ex> R=server_dump
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= <> H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaY-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => CALLER <CALLER@myhost.test.ex> R=server_store T=store
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
diff --git a/test/mail/4510.store b/test/mail/4510.store
new file mode 100644 (file)
index 0000000..d75e409
--- /dev/null
@@ -0,0 +1,58 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from the.local.host.name ([ip4.ip4.ip4.ip4] helo=myhost.test.ex)
+       by myhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaZ-0005vi-00
+       for CALLER@myhost.test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
+       id 10HmaY-0005vi-00
+       for CALLER@myhost.test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: baduser@test.ex
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@myhost.test.ex>
+To: CALLER@myhost.test.ex
+Content-Type: multipart/report; report-type=delivery-status; boundary=NNNNNNNNNN-eximdsn-MMMMMMMMMM
+MIME-Version: 1.0
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: text/plain; charset=us-ascii
+
+This message was created automatically by mail delivery software.
+
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+  baduser@test.ex
+  host ipv4.ipv4.ipv4.ipv4 [ipv4.ipv4.ipv4.ipv4]
+    PRDR error after DATA: 550 PRDR R=<baduser@test.ex> refusal
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/delivery-status
+
+Reporting-MTA: dns; myhost.test.ex
+
+Action: failed
+Final-Recipient: rfc822;baduser@test.ex
+Status: 5.0.0
+Diagnostic-Code: smtp; 550 PRDR R=<baduser@test.ex> refusal
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/rfc822
+
+Return-path: <CALLER@myhost.test.ex>
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+From: nobody@example.com
+From: second@example.com
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+Sender: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+content
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+
index c656cc50bacbb79fe11c7dba2e66a6ebec4edc5e..6b5a3e9d957384489785e26025643be9c9bbc4cf 100755 (executable)
@@ -358,6 +358,7 @@ open(IN, "$file") || tests_exit(-1, "Failed to open $file: $!");
 my($is_log) = $file =~ /log/;
 my($is_stdout) = $file =~ /stdout/;
 my($is_stderr) = $file =~ /stderr/;
+my($is_mail) = $file =~ /mail/;
 
 # Date pattern
 
@@ -1140,6 +1141,13 @@ RESET_AFTER_EXTRA_LINE_READ:
     next if / Berkeley DB error: /;
     }
 
+  elsif ($is_mail)
+    {
+    # Experimental_DSN info in bounces
+    next if /^Remote-MTA: /;
+    next if /^X-Exim-Diagnostic: /;
+    }
+
   # ======== All files other than stderr ========
 
   print MUNGED;
diff --git a/test/scripts/4510-DKIM-Bounces/4510 b/test/scripts/4510-DKIM-Bounces/4510
new file mode 100644 (file)
index 0000000..531dbda
--- /dev/null
@@ -0,0 +1,15 @@
+# DKIM signing and bounces
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# single header signed
+# one rcpt accept, one reject - should get a DSN
+exim -odf baduser@test.ex okuser@test.ex
+From: nobody@example.com
+From: second@example.com
+
+content
+****
+millisleep 500
+killdaemon
diff --git a/test/scripts/4510-DKIM-Bounces/REQUIRES b/test/scripts/4510-DKIM-Bounces/REQUIRES
new file mode 100644 (file)
index 0000000..a75b81c
--- /dev/null
@@ -0,0 +1,2 @@
+support DKIM
+support PRDR