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

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


The following commit(s) were added to refs/heads/9.0.x by this push:
     new 4a7d6755c2 Fix BZ 69728. Remove incorrect h2+optional msg. Improve 
CLIENT-CERT msgs
4a7d6755c2 is described below

commit 4a7d6755c2ba0da0a322d77cd61018e5c95472eb
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jun 26 12:01:08 2025 +0100

    Fix BZ 69728. Remove incorrect h2+optional msg. Improve CLIENT-CERT msgs
    
    https://bz.apache.org/bugzilla/show_bug.cgi?id=69728
---
 .../catalina/authenticator/LocalStrings.properties |  4 +-
 .../catalina/authenticator/SSLAuthenticator.java   | 58 +++++++++++++++-------
 .../tomcat/util/net/AbstractJsseEndpoint.java      |  6 ---
 .../apache/tomcat/util/net/LocalStrings.properties |  1 -
 .../tomcat/util/net/LocalStrings_fr.properties     |  1 -
 .../tomcat/util/net/LocalStrings_ja.properties     |  1 -
 .../tomcat/util/net/LocalStrings_ko.properties     |  1 -
 .../tomcat/util/net/LocalStrings_zh_CN.properties  |  1 -
 webapps/docs/changelog.xml                         |  6 +++
 9 files changed, 49 insertions(+), 30 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/LocalStrings.properties 
b/java/org/apache/catalina/authenticator/LocalStrings.properties
index c30f9afe95..60ec6605ad 100644
--- a/java/org/apache/catalina/authenticator/LocalStrings.properties
+++ b/java/org/apache/catalina/authenticator/LocalStrings.properties
@@ -92,6 +92,6 @@ spnegoAuthenticator.serviceLoginFail=Unable to login as the 
service principal
 spnegoAuthenticator.ticketValidateFail=Failed to validate client supplied 
ticket
 
 sslAuthenticatorValve.authFailed=Authentication with the provided certificates 
failed
-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.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 unless certificateVerification is set to required.
 sslAuthenticatorValve.noCertificates=No certificates are included with this 
request
-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.
+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 unless certificateVerification is set to required.
diff --git a/java/org/apache/catalina/authenticator/SSLAuthenticator.java 
b/java/org/apache/catalina/authenticator/SSLAuthenticator.java
index c384cca466..e5512c92cd 100644
--- a/java/org/apache/catalina/authenticator/SSLAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/SSLAuthenticator.java
@@ -37,6 +37,7 @@ 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;
+import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
 
 /**
  * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication 
that utilizes SSL certificates to identify
@@ -175,28 +176,51 @@ public class SSLAuthenticator extends AuthenticatorBase {
         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));
+            /*
+             * There are two underlying issues here.
+             *
+             * 1. JSSE does not implement post-handshake authentication (PHA) 
for TLS 1.3. That means CLIENT-CERT
+             * authentication will only work if the virtual host requires a 
certificate OR the client never requests a
+             * protected resource.
+             *
+             * 2. HTTP/2 does not permit re-negotiation nor PHA. That means 
CLIENT-CERT authentication will only work if
+             * the virtual host requires a certificate OR the client never 
requests a protected resource.
+             *
+             * We can't rely on the client never requesting a protected 
resource but we can check if all the virtual
+             * hosts are configured to require a certificate.
+             */
+            boolean allHostsRequireCertificate = true;
+            for (SSLHostConfig sslHostConfig : connector.findSslHostConfigs()) 
{
+                if (sslHostConfig.getCertificateVerification() != 
CertificateVerification.REQUIRED) {
+                    allHostsRequireCertificate = false;
                     break;
                 }
             }
 
-            // Then check for TLS 1.3
-            SSLHostConfig[] sslHostConfigs = connector.findSslHostConfigs();
-            for (SSLHostConfig sslHostConfig : sslHostConfigs) {
-                if (!sslHostConfig.isTls13RenegotiationAvailable()) {
-                    String[] enabledProtocols = 
sslHostConfig.getEnabledProtocols();
-                    if (enabledProtocols == null) {
-                        // Possibly boundOnInit is used, so use the less 
accurate protocols
-                        enabledProtocols = 
sslHostConfig.getProtocols().toArray(new String[0]);
+            // Only need to check for use of HTTP/2 or TLS 1.3 if one or more 
hosts doesn't require a certificate
+            if (!allHostsRequireCertificate) {
+                // Check if the Connector is configured to support upgrade to 
HTTP/2
+                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;
                     }
-                    for (String enabledProtocol : enabledProtocols) {
-                        if 
(Constants.SSL_PROTO_TLSv1_3.equals(enabledProtocol)) {
-                            
log.warn(sm.getString("sslAuthenticatorValve.tls13", context.getName(), 
host.getName(),
-                                    connector));
+                }
+
+                // Check if any of the virtual hosts support TLS 1.3 without 
supporting PHA
+                for (SSLHostConfig sslHostConfig : 
connector.findSslHostConfigs()) {
+                    if (!sslHostConfig.isTls13RenegotiationAvailable()) {
+                        String[] enabledProtocols = 
sslHostConfig.getEnabledProtocols();
+                        if (enabledProtocols == null) {
+                            // Possibly boundOnInit is used, so use the less 
accurate protocols
+                            enabledProtocols = 
sslHostConfig.getProtocols().toArray(new String[0]);
+                        }
+                        for (String enabledProtocol : enabledProtocols) {
+                            if 
(Constants.SSL_PROTO_TLSv1_3.equals(enabledProtocol)) {
+                                
log.warn(sm.getString("sslAuthenticatorValve.tls13", context.getName(), 
host.getName(),
+                                        connector));
+                            }
                         }
                     }
                 }
diff --git a/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java 
b/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java
index fae5534abd..c1b095e8fa 100644
--- a/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java
@@ -84,12 +84,6 @@ public abstract class AbstractJsseEndpoint<S, U> extends 
AbstractEndpoint<S,U> {
     @Override
     protected void createSSLContext(SSLHostConfig sslHostConfig) throws 
IllegalArgumentException {
 
-        // HTTP/2 does not permit optional certificate authentication with any
-        // version of TLS.
-        if (sslHostConfig.getCertificateVerification().isOptional() && 
negotiableProtocols.contains("h2")) {
-            
getLog().warn(sm.getString("sslHostConfig.certificateVerificationWithHttp2", 
sslHostConfig.getHostName()));
-        }
-
         boolean firstCertificate = true;
         for (SSLHostConfigCertificate certificate : 
sslHostConfig.getCertificates(true)) {
             SSLUtil sslUtil = sslImplementation.getSSLUtil(certificate);
diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties 
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index c827bdea6d..fe45d03653 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -173,7 +173,6 @@ socketWrapper.writeTimeout=Write timeout
 
 sslHostConfig.certificate.notype=Multiple certificates were specified and at 
least one is missing the required attribute type
 sslHostConfig.certificateVerificationInvalid=The certificate verification 
value [{0}] is not recognised
-sslHostConfig.certificateVerificationWithHttp2=The TLS virtual host [{0}] is 
configured for optional certificate verification and the enclosing connector is 
configured to support upgrade to h2. HTTP/2 over TLS does not permit optional 
certificate verification.
 sslHostConfig.fileNotFound=Configured file [{0}] does not exist
 sslHostConfig.invalid_truststore_password=The provided trust store password 
could not be used to unlock and/or validate the trust store. Retrying to access 
the trust store with a null password which will skip validation.
 sslHostConfig.mismatch=The property [{0}] was set on the SSLHostConfig named 
[{1}] and is for the [{2}] configuration syntax but the SSLHostConfig is being 
used with the [{3}] configuration syntax
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_fr.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_fr.properties
index 3ebc63c7a2..18c67b8348 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_fr.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_fr.properties
@@ -170,7 +170,6 @@ socketWrapper.writeTimeout=Timeout en écriture
 
 sslHostConfig.certificate.notype=Plusieurs certificats ont été spécifiés et au 
moins un n'a pas d'attribut type
 sslHostConfig.certificateVerificationInvalid=La valeur de vérification de 
certificat [{0}] n''est pas reconnue
-sslHostConfig.certificateVerificationWithHttp2=L''hôte virtuel TLS [{0}] est 
configuré avec la validation optionelle du certificat, et le connecteur qui 
l''utilise est configuré pour supporter l''upgrade vers h2. HTTP/2 sur TLS ne 
permet pas la validation optionelle du certificat.
 sslHostConfig.fileNotFound=Le fichier [{0}] configuré n''existe pas.
 sslHostConfig.invalid_truststore_password=Le mot de passe de la base de 
confiance n'a pas pu être utilisé pour déverrouiller et ou valider celle ci, 
nouvel essai en utilisant un mot de passe null pour passer la validation
 sslHostConfig.mismatch=La propriété [{0}] a été fixée sur le SSLHostConfig 
nommé [{1}] et est pour la syntaxe de configuration [{2}] mais le SSLHostConfig 
est utilisé avec la syntaxe de configuration [{3}]
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_ja.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_ja.properties
index 675600a6a5..5fa3415004 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_ja.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_ja.properties
@@ -170,7 +170,6 @@ socketWrapper.writeTimeout=書き込みタイムアウト
 
 sslHostConfig.certificate.notype=指定された複数の証明書の中に、少なくとも1つは必須要素の存在しない証明書が含まれています。
 sslHostConfig.certificateVerificationInvalid=証明書検証値[{0}]が認識されません
-sslHostConfig.certificateVerificationWithHttp2=TLS仮想ホスト[{0}]はオプションの証明書検証用に構成されており、コネクタはh2へのアップグレードをサポートするように構成されています。
 HTTP/2 over TLSでは、オプションの証明書検証は許可されていません。
 sslHostConfig.fileNotFound=構成ファイル[{0}]は存在しません
 
sslHostConfig.invalid_truststore_password=提供されたトラストストアパスワードは、トラストストアのロック解除および検証に使用できませんでした。
 検証をスキップするnullパスワードでトラストストアにアクセスしようとしました。
 sslHostConfig.mismatch=[{0}] プロパティは [{1}] という名前のSSLHostConfigで設定され、[{2}] 
構成構文用ですが、[{3}] 構成構文でSSLHostConfigが使用されています
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_ko.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_ko.properties
index b1aeccc75a..2d5ff57459 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_ko.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_ko.properties
@@ -160,7 +160,6 @@ socketWrapper.writeTimeout=쓰기 타임아웃
 
 sslHostConfig.certificate.notype=여러 개의 인증서들이 지정되었는데, 적어도 하나의 인증서에 필수 속성 타입이 
없습니다.
 sslHostConfig.certificateVerificationInvalid=인증서 검증 값 [{0}]은(는) 인식되지 않는 값입니다.
-sslHostConfig.certificateVerificationWithHttp2=TLS 가상 호스트 [{0}](은)는 선택적 인증서 
확인을 하도록 설정되었고, 내부에 정의된 커넥터는 HTTP/2로 업그레이드를 지원하도록 설정되었습니다. TLS 기반의 HTTP/2는 선택적 
인증서 확인을 허용하지 않습니다.
 sslHostConfig.fileNotFound=설정된 파일 [{0}]이(가) 존재하지 않습니다.
 sslHostConfig.invalid_truststore_password=Trust 저장소를 잠금을 풀거나 유효한지 확인하는 용도로, 
제공된 Trust 저장소 비밀번호를 사용할 수 없었습니다. 널 비밀번호를 사용하여, 해당 Trust 저장소에 대한 접근을 다시 시도합니다. 
이는 유효한지 확인하는 작업을 건너뛸 것입니다.
 sslHostConfig.mismatch=[{1}](이)라는 이름의 SSLHostConfig에 프로퍼티 [{0}]이(가) 설정되었는데, 이 
프로퍼티는 [{2}] 설정 문법을 위한 것이나, 해당 SSLHostConfig은 [{3}] 설정 문법으로 사용되고 있습니다.
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties
index 123716ffa8..6deb4a8716 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties
@@ -162,7 +162,6 @@ socketWrapper.writeTimeout=写入超时
 
 sslHostConfig.certificate.notype=指定了多个证书,并且至少有一个证书缺少必需的属性类型
 sslHostConfig.certificateVerificationInvalid=证书认证值[{0}]未识别
-sslHostConfig.certificateVerificationWithHttp2=TLS虚拟主机[{0}]被配置为可选的证书验证,包围的连接器被配置为支持升级到h2。HTTP/2
 over TLS不允许可选的证书验证。
 sslHostConfig.fileNotFound=配置文件 [{0}] 不存在
 
sslHostConfig.invalid_truststore_password=提供的信任存储密码无法用于解锁和/或验证信任存储。正在重试使用空密码访问信任存储,该密码将跳过验证。
 sslHostConfig.mismatch=属性[{0}]是在名为[{1}]的SSLHostConfig 
上设置的,用于[{2}]配置语法,但SSLHostConfig 正与[{3}]配置语法一起使用
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 04336f0129..2b0bffbd85 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -148,6 +148,12 @@
       <fix>
         Improve stability of APR/native connector. (markt)
       </fix>
+      <fix>
+        <bug>69728</bug>: Remove incorrect warning when HTTP/2 is used with
+        optional certificate verification and improve the warnings when a web
+        application tries to use CLIENT-CERT with either HTTP/2 or a JSSE
+        implementation of TLS 1.3. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">


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

Reply via email to