You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2022/03/24 16:19:57 UTC

[tomcat] branch 10.0.x updated: Log a warning for CLIENT-CERT + JSSE TLS 1.3 as PHA is not supported

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

markt pushed a commit to branch 10.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.0.x by this push:
     new 0d5fdc3  Log a warning for CLIENT-CERT + JSSE TLS 1.3 as PHA is not supported
0d5fdc3 is described below

commit 0d5fdc30f379c060fe5ccb7301231152f4341f16
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Mar 24 16:19:09 2022 +0000

    Log a warning for CLIENT-CERT + JSSE TLS 1.3 as PHA is not supported
    
    CLIENT-CERT requires post-handshake authentication (PHA) to work with
    TLS 1.3 but the JSSE TLS 1.3 implementation does not support PHA.
---
 .../catalina/authenticator/LocalStrings.properties |  3 +
 .../catalina/authenticator/SSLAuthenticator.java   | 70 ++++++++++++++++++++++
 java/org/apache/tomcat/util/net/SSLHostConfig.java | 12 ++++
 java/org/apache/tomcat/util/net/SSLUtilBase.java   |  6 +-
 webapps/docs/changelog.xml                         | 10 +++-
 5 files changed, 98 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/LocalStrings.properties b/java/org/apache/catalina/authenticator/LocalStrings.properties
index 0030ce3..81acc29 100644
--- a/java/org/apache/catalina/authenticator/LocalStrings.properties
+++ b/java/org/apache/catalina/authenticator/LocalStrings.properties
@@ -70,3 +70,6 @@ spnegoAuthenticator.authHeaderNoToken=The Negotiate authorization header sent by
 spnegoAuthenticator.authHeaderNotNego=The authorization header sent by the client did not start with Negotiate
 spnegoAuthenticator.serviceLoginFail=Unable to login as the service principal
 spnegoAuthenticator.ticketValidateFail=Failed to validate client supplied ticket
+
+sslAuthenticatorValve.http2=The context [{0}] in virtual host [{1}] is configured to use CLIENT-CERT authentication and [{2}] is configured to support HTTP/2. Use of CLIENT-CERT authentication is not compatible with the use of HTTP/2.
+sslAuthenticatorValve.tls13=The context [{0}] in virtual host [{1}] is configured to use CLIENT-CERT authentication and [{2}] is configured to support TLS 1.3 using JSSE. Use of CLIENT-CERT authentication is not compatible with the use of TLS 1.3 and JSSE.
diff --git a/java/org/apache/catalina/authenticator/SSLAuthenticator.java b/java/org/apache/catalina/authenticator/SSLAuthenticator.java
index 9844b22..30344b9 100644
--- a/java/org/apache/catalina/authenticator/SSLAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/SSLAuthenticator.java
@@ -23,9 +23,20 @@ import java.security.cert.X509Certificate;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
 import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.connector.Connector;
 import org.apache.catalina.connector.Request;
 import org.apache.coyote.ActionCode;
+import org.apache.coyote.UpgradeProtocol;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.net.Constants;
+import org.apache.tomcat.util.net.SSLHostConfig;
 
 /**
  * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication
@@ -35,6 +46,8 @@ import org.apache.coyote.ActionCode;
  */
 public class SSLAuthenticator extends AuthenticatorBase {
 
+    private final Log log = LogFactory.getLog(SSLAuthenticator.class); // must not be static
+
     /**
      * Authenticate the user by checking for the existence of a certificate
      * chain, validating it against the trust manager for the connector and then
@@ -137,4 +150,61 @@ public class SSLAuthenticator extends AuthenticatorBase {
 
         return certs;
     }
+
+
+    @Override
+    protected synchronized void startInternal() throws LifecycleException {
+
+        super.startInternal();
+
+        /*
+         * This Valve should only ever be added to a Context and if the Context
+         * is started there should always be a Host and an Engine but test at
+         * each stage to be safe.
+         */
+        Container container = getContainer();
+        if (!(container instanceof Context)) {
+            return;
+        }
+        Context context = (Context) container;
+
+        container = context.getParent();
+        if (!(container instanceof Host)) {
+            return;
+        }
+        Host host = (Host) container;
+
+        container = host.getParent();
+        if (!(container instanceof Engine)) {
+            return;
+        }
+        Engine engine = (Engine) container;
+
+
+        Connector[] connectors = engine.getService().findConnectors();
+
+        for (Connector connector : connectors) {
+            // First check for upgrade
+            UpgradeProtocol[] upgradeProtocols = connector.findUpgradeProtocols();
+            for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
+                if ("h2".equals(upgradeProtocol.getAlpnName())) {
+                    log.warn(sm.getString("sslAuthenticatorValve.http2", context.getName(), host.getName(), connector));
+                    break;
+                }
+            }
+
+            // Then check for TLS 1.3
+            SSLHostConfig[] sslHostConfigs = connector.findSslHostConfigs();
+            for (SSLHostConfig sslHostConfig : sslHostConfigs) {
+                if (!sslHostConfig.isTls13RenegotiationAvailable()) {
+                    String[] enabledProtocols = sslHostConfig.getEnabledProtocols();
+                    for (String enbabledProtocol : enabledProtocols) {
+                        if (Constants.SSL_PROTO_TLSv1_3.equals(enbabledProtocol)) {
+                            log.warn(sm.getString("sslAuthenticatorValve.tls13", context.getName(), host.getName(), connector));
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/java/org/apache/tomcat/util/net/SSLHostConfig.java b/java/org/apache/tomcat/util/net/SSLHostConfig.java
index 81552f4..9a06c52 100644
--- a/java/org/apache/tomcat/util/net/SSLHostConfig.java
+++ b/java/org/apache/tomcat/util/net/SSLHostConfig.java
@@ -77,6 +77,8 @@ public class SSLHostConfig implements Serializable {
     // reference is held on the certificate.
     private transient Long openSslContext = Long.valueOf(0);
 
+    private boolean tls13RenegotiationAvailable = false;
+
     // Configuration properties
 
     // Internal
@@ -130,6 +132,16 @@ public class SSLHostConfig implements Serializable {
     }
 
 
+    public boolean isTls13RenegotiationAvailable() {
+        return tls13RenegotiationAvailable;
+    }
+
+
+    public void setTls13RenegotiationAvailable(boolean tls13RenegotiationAvailable) {
+        this.tls13RenegotiationAvailable = tls13RenegotiationAvailable;
+    }
+
+
     public Long getOpenSslConfContext() {
         return openSslConfContext;
     }
diff --git a/java/org/apache/tomcat/util/net/SSLUtilBase.java b/java/org/apache/tomcat/util/net/SSLUtilBase.java
index 0cac954..0c73006 100644
--- a/java/org/apache/tomcat/util/net/SSLUtilBase.java
+++ b/java/org/apache/tomcat/util/net/SSLUtilBase.java
@@ -58,7 +58,6 @@ import javax.net.ssl.X509KeyManager;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.file.ConfigFileLoader;
-import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
 import org.apache.tomcat.util.net.jsse.JSSEKeyManager;
 import org.apache.tomcat.util.net.jsse.PEMFile;
 import org.apache.tomcat.util.res.StringManager;
@@ -113,11 +112,14 @@ public abstract class SSLUtilBase implements SSLUtil {
         this.enabledProtocols = enabledProtocols.toArray(new String[0]);
 
         if (enabledProtocols.contains(Constants.SSL_PROTO_TLSv1_3) &&
-                sslHostConfig.getCertificateVerification() == CertificateVerification.OPTIONAL &&
+                sslHostConfig.getCertificateVerification().isOptional() &&
                 !isTls13RenegAuthAvailable() && warnTls13) {
             log.warn(sm.getString("sslUtilBase.tls13.auth"));
         }
 
+        // Make TLS 1.3 renegotiation status visible further up the stack
+        sslHostConfig.setTls13RenegotiationAvailable(isTls13RenegAuthAvailable());
+
         // Calculate the enabled ciphers
         List<String> configuredCiphers = sslHostConfig.getJsseCipherNames();
         Set<String> implementedCiphers = getImplementedCiphers();
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index e02fbd1..cf748f2 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -125,11 +125,19 @@
         by Thomas Hoffmann. (remm)
       </fix>
       <add>
-        <bug>65975</bug>: Add a warning if a TLS vitual host is configured with
+        <bug>65975</bug>: Add a warning if a TLS virtual host is configured with
         optional certificate authentication and the containing connector is also
         configured to support HTTP/2 as HTTP/2 does not permit optional
         certificate authentication. (markt)
       </add>
+      <add>
+        <bug>65975</bug>: Add a warning if a TLS virtual host is configured for
+        TLS 1.3 with a JSSE implementation and a web application is configured
+        for <code>CLIENT-CERT</code> authentication. <code>CLIENT-CERT</code>
+        authentication requires post-handshake authentication (PHA) when used
+        with TLS 1.3 but the JSSE TLS 1.3 implementation does not support PHA.
+        (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Jasper">

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org