This is an automated email from the ASF dual-hosted git repository.

bodewig pushed a commit to branch mailer-tls-server-check
in repository https://gitbox.apache.org/repos/asf/ant.git

commit 6154296c226e07bceb944f40d7ed071a49c945c4
Author: Stefan Bodewig <bode...@apache.org>
AuthorDate: Sat May 31 16:30:35 2025 +0200

    improve security of TLS handling in MimeMailers
    
    Bugzilla Report https://bz.apache.org/bugzilla/show_bug.cgi?id=69416
---
 WHATSNEW                                           | 12 ++++++++
 manual/Tasks/mail.html                             | 17 +++++++++++
 manual/listeners.html                              | 16 ++++++++++
 .../org/apache/tools/ant/listener/MailLogger.java  | 27 +++++++++++++++++
 .../apache/tools/ant/taskdefs/email/EmailTask.java | 29 ++++++++++++++++++
 .../ant/taskdefs/email/JakartaMimeMailer.java      |  9 ++++++
 .../apache/tools/ant/taskdefs/email/Mailer.java    | 35 ++++++++++++++++++++++
 .../tools/ant/taskdefs/email/MimeMailer.java       |  9 ++++++
 8 files changed, 154 insertions(+)

diff --git a/WHATSNEW b/WHATSNEW
index 3cba7a7b4..194e00786 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -18,6 +18,14 @@ Changes that could break older environments:
    the behavior of 1.10.15.
    Bugzilla Report 65756
 
+ * the <mail> task as well as MailLogger will now check the server
+   identity as specified by RFC 2595 when JavaMail is used in
+   combination with TLS (plain TLS or StartTLS).
+   The check can be disabled with a new MailLogger property
+   MailLogger.tls.checkserveridentity or a new <mail> task attribute
+   checkServerIdentity.
+   Bugzilla Report 69416
+
 Fixed bugs:
 -----------
 
@@ -40,6 +48,10 @@ Other changes:
    "disallow".
    Github Pull Request #216
 
+ * <mail> and MailLogger can now enforce the use of STARTLS rather
+   than silently fall back to unencrypted authentication via a new
+   MailLogger property and a new <mail> task attribute.
+   Bugzilla Report 69416
 
 Changes from Ant 1.10.14 TO Ant 1.10.15
 =======================================
diff --git a/manual/Tasks/mail.html b/manual/Tasks/mail.html
index 3b51a64c4..2c43a6066 100644
--- a/manual/Tasks/mail.html
+++ b/manual/Tasks/mail.html
@@ -171,6 +171,23 @@ <h3>Parameters</h3>
       1.8.0</em></td>
     <td>No</td>
   </tr>
+  <tr>
+    <td>requireStartTLS</td>
+    <td>(boolean) Whether the <code>STARTTLS</code> command used to switch to 
an encrypted
+      connection for authentication should be required.
+      <br/>Implicitly sets <q>enableStartTLS</q> to <q>true</q> if enabled. 
Requires JavaMail.
+      <br/><em>Since Ant 1.10.16</em></td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>checkServerIdentity</td>
+    <td>(boolean) Whether the server's identity shall be verified
+      during TLS handshake.
+      <br/> Ignored unless <q>ssl</q> or <q>enableStartTLS</q> is <q>true</q>.
+      Requires JavaMail.
+      <br/><em>Since Ant 1.10.16</em></td>
+    <td>No; default is <q>true</q></td>
+  </tr>
 </table>
 
 <h3>Note regarding the attributes containing email addresses</h3>
diff --git a/manual/listeners.html b/manual/listeners.html
index 4c1b87801..286d58f6b 100644
--- a/manual/listeners.html
+++ b/manual/listeners.html
@@ -259,6 +259,22 @@ <h3 id="MailLogger">MailLogger</h3>
       1.8.0</em></td>
     <td>No; default is <q>false</q></td>
   </tr>
+  <tr>
+    <td><code>MailLogger.starttls.require</code></td>
+    <td>on or true if <code>STARTTLS</code> should be required
+      (requires JavaMail).
+      If <q>true</q> implicitly
+      sets <code>MailLogger.starttls.enable</code> to <q>true</q> as well.
+      <br/><em>Since Ant 1.10.16</em></td>
+    <td>No; default is <q>false</q></td>
+  </tr>
+  <tr>
+    <td><code>MailLogger.tls.checkserveridentity</code></td>
+    <td>on or true if the identity of the server shall be chcked
+      during the TLS handshake (requires JavaMail).
+      <br/><em>Since Ant 1.10.16</em></td>
+    <td>No; default is <q>true</q></td>
+  </tr>
   <tr>
     <td><code>MailLogger.properties.file</code></td>
     <td>Filename of properties file that will override other values.</td>
diff --git a/src/main/org/apache/tools/ant/listener/MailLogger.java 
b/src/main/org/apache/tools/ant/listener/MailLogger.java
index 897f0000b..5a26b30a1 100644
--- a/src/main/org/apache/tools/ant/listener/MailLogger.java
+++ b/src/main/org/apache/tools/ant/listener/MailLogger.java
@@ -84,6 +84,11 @@ import org.apache.tools.mail.MailMessage;
  *    <li> MailLogger.charset [no default] - character set of email</li>
  *    <li> MailLogger.starttls.enable [default: false] - on or true if
  *    STARTTLS should be supported (requires Java or Jakarta Mail)</li>
+ *    <li> MailLogger.starttls.require [default: false] - on or true if
+ *    STARTTLS should be required (requires Java or Jakarta Mail)</li>
+ *    <li> MailLogger.tls.checkserveridentity [default: true] - on or true if
+ *    the identity of the server shall be chcked during the TLS handshake
+ *    (requires Java or Jakarta Mail)</li>
  *    <li> MailLogger.properties.file [no default] - Filename of
  *    properties file that will override other values.</li>
  *  </ul>
@@ -153,6 +158,10 @@ public class MailLogger extends DefaultLogger {
                                                 "ssl", "off")))
                 .starttls(Project.toBoolean(getValue(properties,
                                                      "starttls.enable", 
"off")))
+                .starttlsRequired(Project.toBoolean(getValue(properties,
+                                                             
"starttls.require", "off")))
+                .checkTlsServerIdentity(Project.toBoolean(getValue(properties,
+                                                                   
"tls.checkserveridentity", "on")))
                 .from(getValue(properties, "from", null))
                 .replytoList(getValue(properties, "replyto", ""))
                 .toList(getValue(properties, prefix + ".to", null))
@@ -299,6 +308,22 @@ public class MailLogger extends DefaultLogger {
             this.starttls = starttls;
             return this;
         }
+        private boolean starttlsRequired;
+        public boolean starttlsRequired() {
+            return starttlsRequired;
+        }
+        public Values starttlsRequired(boolean required) {
+            this.starttlsRequired = required;
+            return required ? starttls(required) : this;
+        }
+        private boolean checkTlsServerIdentity = true;
+        public boolean checkTlsServerIdentity() {
+            return checkTlsServerIdentity;
+        }
+        public Values checkTlsServerIdentity(boolean check) {
+            this.checkTlsServerIdentity = check;
+            return this;
+        }
     }
 
     /**
@@ -400,6 +425,8 @@ public class MailLogger extends DefaultLogger {
         mailer.setPassword(values.password());
         mailer.setSSL(values.ssl());
         mailer.setEnableStartTLS(values.starttls());
+        mailer.setRequireStartTLS(values.starttlsRequired());
+        mailer.setCheckServerIdentity(values.checkTlsServerIdentity());
         Message mymessage =
             new Message(!values.body().isEmpty() ? values.body() : message);
         mymessage.setProject(project);
diff --git a/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java 
b/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java
index 5336d06fd..44e166287 100644
--- a/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java
@@ -105,10 +105,14 @@ public class EmailTask extends Task {
     private boolean ssl = false;
     /** indicate if the user wishes support for STARTTLS */
     private boolean starttls = false;
+    private boolean requireStarttls = false;
 
     /** ignore invalid recipients? */
     private boolean ignoreInvalidRecipients = false;
 
+    /** more strict TLS server certificate check */
+    private boolean checkServerIdentity = true;
+
     /**
      * Set the user for SMTP auth; this requires JavaMail.
      *
@@ -150,6 +154,29 @@ public class EmailTask extends Task {
         this.starttls = b;
     }
 
+    /**
+     * Set whether to require authentication to switch to a TLS
+     * connection via STARTTLS.
+     *
+     * @param b boolean; if true STARTTLS will be supported and required.
+     * @since Ant 1.10.16
+     */
+    public void setRequireStartTLS(boolean b) {
+        this.requireStarttls = b;
+        if (b) {
+            setEnableStartTLS(b);
+        }
+    }
+
+    /**
+     * Whether the server's identity shall be verified during TLS handshake.
+     * @param b boolean; if true server identity will be checked.
+     * @since Ant 1.10.16
+     */
+    public void setCheckServerIdentity(boolean b) {
+        this.checkServerIdentity = b;
+    }
+
     /**
      * Set the preferred encoding method.
      *
@@ -557,6 +584,8 @@ public class EmailTask extends Task {
             mailer.setPassword(password);
             mailer.setSSL(ssl);
             mailer.setEnableStartTLS(starttls);
+            mailer.setRequireStartTLS(requireStarttls);
+            mailer.setCheckServerIdentity(checkServerIdentity);
             mailer.setMessage(message);
             mailer.setFrom(from);
             mailer.setReplyToList(replyToList);
diff --git 
a/src/main/org/apache/tools/ant/taskdefs/email/JakartaMimeMailer.java 
b/src/main/org/apache/tools/ant/taskdefs/email/JakartaMimeMailer.java
index 0055c5ffc..e41d3d805 100644
--- a/src/main/org/apache/tools/ant/taskdefs/email/JakartaMimeMailer.java
+++ b/src/main/org/apache/tools/ant/taskdefs/email/JakartaMimeMailer.java
@@ -155,6 +155,9 @@ public class JakartaMimeMailer extends Mailer {
                     props.put("mail.smtp.socketFactory.port",
                               String.valueOf(port));
                 }
+                if (shouldCheckServerIdentity()) {
+                    props.put("mail.smtp.ssl.checkserveridentity", "true");
+                }
             }
             if (user != null || password != null) {
                 props.put("mail.smtp.auth", "true");
@@ -162,6 +165,12 @@ public class JakartaMimeMailer extends Mailer {
             }
             if (isStartTLSEnabled()) {
                 props.put("mail.smtp.starttls.enable", "true");
+                if (isStartTLSRequired()) {
+                    props.put("mail.smtp.starttls.required", "true");
+                }
+                if (shouldCheckServerIdentity()) {
+                    props.put("mail.smtp.ssl.checkserveridentity", "true");
+                }
             }
             sesh = Session.getInstance(props, auth);
 
diff --git a/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java 
b/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java
index 7c00038a3..12ee973a3 100644
--- a/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java
+++ b/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java
@@ -52,7 +52,9 @@ public abstract class Mailer {
     // CheckStyle:VisibilityModifier ON
     private boolean ignoreInvalidRecipients = false;
     private boolean starttls = false;
+    private boolean requireStarttls = false;
     private boolean portExplicitlySpecified = false;
+    private boolean checkServerIdentity = true;
 
     /**
      * Set the mail server.
@@ -136,6 +138,25 @@ public abstract class Mailer {
         return starttls;
     }
 
+    /**
+     * Set whether to enforce authentication to switch to a TLS
+     * connection via STARTTLS.
+     * @param b boolean; if true STARTTLS will be required.
+     * @since Ant 1.10.16
+     */
+    public void setRequireStartTLS(boolean b) {
+        this.requireStarttls = b;
+    }
+
+    /**
+     * Whether the server's identity shall be verified during TLS handshake.
+     * @param b boolean; if true server identity will be checked.
+     * @since Ant 1.10.16
+     */
+    public void setCheckServerIdentity(boolean b) {
+        this.checkServerIdentity = b;
+    }
+
     /**
      * Set the message.
      *
@@ -268,6 +289,20 @@ public abstract class Mailer {
         return ignoreInvalidRecipients;
     }
 
+    /**
+     * @since Ant 1.10.16
+     */
+    protected boolean shouldCheckServerIdentity() {
+        return starttls;
+    }
+
+    /**
+     * @since Ant 1.10.16
+     */
+    protected boolean isStartTLSRequired() {
+        return requireStarttls;
+    }
+
     /**
      * Return the current Date in a format suitable for a SMTP date
      * header.
diff --git a/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java 
b/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java
index 6a55312d3..0d3598604 100644
--- a/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java
+++ b/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java
@@ -157,6 +157,9 @@ public class MimeMailer extends Mailer {
                     props.put("mail.smtp.socketFactory.port",
                               String.valueOf(port));
                 }
+                if (shouldCheckServerIdentity()) {
+                    props.put("mail.smtp.ssl.checkserveridentity", "true");
+                }
             }
             if (user != null || password != null) {
                 props.put("mail.smtp.auth", "true");
@@ -164,6 +167,12 @@ public class MimeMailer extends Mailer {
             }
             if (isStartTLSEnabled()) {
                 props.put("mail.smtp.starttls.enable", "true");
+                if (isStartTLSRequired()) {
+                    props.put("mail.smtp.starttls.required", "true");
+                }
+                if (shouldCheckServerIdentity()) {
+                    props.put("mail.smtp.ssl.checkserveridentity", "true");
+                }
             }
             sesh = Session.getInstance(props, auth);
 

Reply via email to