This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 2f5925a16cdec0d0e70ce4adf0e2fefbeb2225f4 Author: opencode <[email protected]> AuthorDate: Thu Oct 15 14:46:02 2026 +0200 Report a configuration error for PEM certificates with a FIPS key manager When the KeyManagerFactory is provided by a FIPS module, Tomcat passes the configured key store to the factory directly and skips the manipulation of key material that FIPS does not allow. PEM format certificates require that manipulation: the key and certificate chain are read from the PEM files and imported into an in memory key store. Previously, the FIPS code path used the configured key store without checking it. For a PEM based configuration there is no key store, so the factory was initialised with a null key store. Depending on the implementation, that either produced a key manager with no keys, allowing the connector to start but causing every TLS handshake to fail, or an unrelated error during start up. Now report the configuration error when no key store is available. The existing message is used when no certificate has been configured at all, as for a non-FIPS configuration. Otherwise, explain that PEM format certificate files require a key store when a FIPS key manager factory is in use. Tests: testFipsWithPemConfiguration and testFipsWithoutConfiguration cover both cases. Both previously failed because no error was reported. --- .../apache/tomcat/util/net/LocalStrings.properties | 1 + java/org/apache/tomcat/util/net/SSLUtilBase.java | 10 +++++ .../util/net/TestKeyManagerWrappingFips.java | 46 ++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties b/java/org/apache/tomcat/util/net/LocalStrings.properties index fafd60f078..6bc78573bd 100644 --- a/java/org/apache/tomcat/util/net/LocalStrings.properties +++ b/java/org/apache/tomcat/util/net/LocalStrings.properties @@ -172,6 +172,7 @@ sslImplementation.cnfe=Unable to create SSLImplementation for class [{0}] sslUtilBase.active=The [{0}] that are active are : [{1}] sslUtilBase.aliasIgnored=FIPS enabled so alias name [{0}] will be ignored. If there is more than one key in the key store, the key used will depend on the key store implementation sslUtilBase.alias_no_key_entry=Alias name [{0}] does not identify a key entry +sslUtilBase.fipsPemNotSupported=FIPS enabled so PEM format certificate files are not supported. Configure the certificate using a key store rather than the certificateFile attribute sslUtilBase.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager sslUtilBase.keystore_load_failed=Failed to load keystore type [{0}] with path [{1}] due to [{2}] sslUtilBase.noCertFile=SSLHostConfig attribute certificateFile must be defined when using an SSL connector diff --git a/java/org/apache/tomcat/util/net/SSLUtilBase.java b/java/org/apache/tomcat/util/net/SSLUtilBase.java index 89c1860c77..68ac2ecbb8 100644 --- a/java/org/apache/tomcat/util/net/SSLUtilBase.java +++ b/java/org/apache/tomcat/util/net/SSLUtilBase.java @@ -353,6 +353,16 @@ public abstract class SSLUtilBase implements SSLUtil { if (keyAlias != null) { log.warn(sm.getString("sslUtilBase.aliasIgnored", keyAlias)); } + if (ks == null) { + if (certificate.getCertificateFile() == null) { + throw new IOException(sm.getString("sslUtilBase.noCertFile")); + } + // Importing PEM format certificates into an in memory key store + // requires the key manipulation that is avoided above. Passing a + // null key store to the factory would result in a key manager + // with no keys and every TLS handshake would then fail. + throw new IOException(sm.getString("sslUtilBase.fipsPemNotSupported")); + } kmf.init(ksUsed, keyPassArray); return kmf.getKeyManagers(); } diff --git a/test/org/apache/tomcat/util/net/TestKeyManagerWrappingFips.java b/test/org/apache/tomcat/util/net/TestKeyManagerWrappingFips.java index 3f1e9e2e31..7b2928f570 100644 --- a/test/org/apache/tomcat/util/net/TestKeyManagerWrappingFips.java +++ b/test/org/apache/tomcat/util/net/TestKeyManagerWrappingFips.java @@ -18,6 +18,7 @@ package org.apache.tomcat.util.net; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; @@ -74,6 +75,51 @@ public class TestKeyManagerWrappingFips { getKeyManagers(); Assert.assertTrue(DummyKeyStoreSpi.wrappingOccurred); } + + + @Test + public void testFipsWithPemConfiguration() throws Exception { + Security.addProvider(new DummyKeyManagerFactoryProvider(FIPS_PROVIDER, + "Sun JSSE provider (FIPS mode, crypto provider SunPKCS11-NSSfips", DUMMY_ALGORITHM)); + + SSLHostConfigCertificate certificate = getCertificate(); + certificate.setCertificateFile("server.crt"); + + try { + new JSSEUtil(certificate).getKeyManagers(); + Assert.fail("PEM format certificates are not supported with a FIPS key manager factory"); + } catch (IOException ioe) { + // Before the FIPS branch checked for a key store, the key manager + // factory was initialised with a null key store. That produced a key + // manager with no keys which failed every TLS handshake with an + // unrelated error rather than reporting the configuration error. + Assert.assertTrue(ioe.getMessage(), ioe.getMessage().contains("PEM")); + } + } + + + @Test + public void testFipsWithoutConfiguration() throws Exception { + Security.addProvider(new DummyKeyManagerFactoryProvider(FIPS_PROVIDER, + "Sun JSSE provider (FIPS mode, crypto provider SunPKCS11-NSSfips", DUMMY_ALGORITHM)); + + try { + new JSSEUtil(getCertificate()).getKeyManagers(); + Assert.fail("A certificate configuration is required"); + } catch (IOException ioe) { + // Ignore. This is the standard error for a missing certificate file. + Assert.assertFalse(ioe.getMessage(), ioe.getMessage().contains("PEM")); + } + } + + + private SSLHostConfigCertificate getCertificate() { + SSLHostConfig hostConfig = new SSLHostConfig(); + hostConfig.setKeyManagerAlgorithm(DUMMY_ALGORITHM); + return new SSLHostConfigCertificate(hostConfig, SSLHostConfigCertificate.Type.UNDEFINED); + } + + private void getKeyManagers() throws Exception { Security.addProvider(new DummyKeyStoreProvider(KEYSTORE_PROVIDER, "", DUMMY_KEYSTORE)); SSLHostConfig hostConfig = new SSLHostConfig(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
