diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java index f1d1b164bcf..b8d57932923 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java @@ -172,7 +172,7 @@ protected void initEngine(SSLEngine sslEngine) { private String[] getEnabledProtocols(final ZKConfig config) { String enabledProtocolsInput = config.getProperty(getSslEnabledProtocolsProperty()); if (enabledProtocolsInput == null) { - return new String[]{ config.getProperty(getSslProtocolProperty(), DEFAULT_PROTOCOL) }; + return null; } return enabledProtocolsInput.split(","); } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java index 9cfa79bc1cb..7163da640eb 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java @@ -35,7 +35,6 @@ import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXRevocationChecker; import java.security.cert.X509CertSelector; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -95,25 +94,38 @@ public abstract class X509Util implements Closeable, AutoCloseable { } } - public static final String DEFAULT_PROTOCOL = defaultTlsProtocol(); + private static final AtomicReference defaultProtocol = new AtomicReference<>(); /** - * Return TLSv1.3 or TLSv1.2 depending on Java runtime version being used. + * Return TLSv1.2 when FIPS mode is enabled. + * Otherwise, returns TLSv1.3 or TLSv1.2 depending on Java runtime version being used. * TLSv1.3 was first introduced in JDK11 and back-ported to OpenJDK 8u272. */ - private static String defaultTlsProtocol() { - String defaultProtocol = TLS_1_2; - List supported = new ArrayList<>(); + public static String defaultTlsProtocol(ZKConfig config) { + if (getFipsMode(config)) { + return TLS_1_2; + } + + String proto = defaultProtocol.get(); + if (proto != null) { + return proto; + } + + proto = TLS_1_2; try { - supported = Arrays.asList(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); + List supported = Arrays.asList(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); if (supported.contains(TLS_1_3)) { - defaultProtocol = TLS_1_3; + proto = TLS_1_3; + } + if (defaultProtocol.compareAndSet(null, proto)) { + LOG.info("Supported TLS protocols are {}, default TLS protocol is {}", supported, proto); + } else { + proto = defaultProtocol.get(); } } catch (NoSuchAlgorithmException e) { // Ignore. } - LOG.info("Default TLS protocol is {}, supported TLS protocols are {}", defaultProtocol, supported); - return defaultProtocol; + return proto; } // ChaCha20 was introduced in OpenJDK 11.0.15 and it is not supported by JDK8. @@ -467,8 +479,8 @@ public SSLContextAndOptions createSSLContextAndOptionsFromConfig(ZKConfig config + trustStoreTypeProp, e); } } - - String protocol = config.getProperty(sslProtocolProperty, DEFAULT_PROTOCOL); + String defaultTlsProtocol = defaultTlsProtocol(config); + String protocol = config.getProperty(sslProtocolProperty, defaultTlsProtocol); try { SSLContext sslContext = SSLContext.getInstance(protocol); sslContext.init(keyManagers, trustManagers, null); diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java index b5ac140ff5e..26615660f51 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java @@ -18,6 +18,9 @@ package org.apache.zookeeper.common; +import static org.apache.zookeeper.common.X509Util.FIPS_MODE_PROPERTY; +import static org.apache.zookeeper.common.X509Util.TLS_1_2; +import static org.apache.zookeeper.common.X509Util.TLS_1_3; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -90,6 +93,7 @@ public void cleanUp() { System.clearProperty(x509Util.getSslHandshakeDetectionTimeoutMillisProperty()); System.clearProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY); System.clearProperty(ZKClientConfig.ZOOKEEPER_CLIENT_CNXN_SOCKET); + System.clearProperty(FIPS_MODE_PROPERTY); x509Util.close(); } @@ -100,24 +104,39 @@ public void testCreateSSLContextWithoutCustomProtocol( X509KeyType caKeyType, X509KeyType certKeyType, String keyPassword, Integer paramIndex) throws Exception { init(caKeyType, certKeyType, keyPassword, paramIndex); + System.setProperty(FIPS_MODE_PROPERTY, Boolean.FALSE.toString()); SSLContext sslContext = x509Util.getDefaultSSLContext(); - assertEquals(X509Util.DEFAULT_PROTOCOL, sslContext.getProtocol()); + String defaultTlsProtocol = X509Util.defaultTlsProtocol(new ZKConfig()); + assertEquals(defaultTlsProtocol, sslContext.getProtocol()); // Check that TLSv1.3 is selected in JDKs that support it (OpenJDK 8u272 and later). List supported = Arrays.asList(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); - if (supported.contains(X509Util.TLS_1_3)) { + if (supported.contains(TLS_1_3)) { // SSLContext protocol. - assertEquals(X509Util.TLS_1_3, sslContext.getProtocol()); + assertEquals(TLS_1_3, sslContext.getProtocol()); // Enabled protocols. List protos = Arrays.asList(sslContext.getDefaultSSLParameters().getProtocols()); - assertTrue(protos.contains(X509Util.TLS_1_2)); - assertTrue(protos.contains(X509Util.TLS_1_3)); + assertTrue(protos.contains(TLS_1_2)); + assertTrue(protos.contains(TLS_1_3)); } else { - assertEquals(X509Util.TLS_1_2, sslContext.getProtocol()); - assertArrayEquals(new String[]{X509Util.TLS_1_2}, sslContext.getDefaultSSLParameters().getProtocols()); + assertEquals(TLS_1_2, sslContext.getProtocol()); + assertArrayEquals(new String[]{TLS_1_2}, sslContext.getDefaultSSLParameters().getProtocols()); } } + @ParameterizedTest + @MethodSource("data") + @Timeout(value = 5) + public void testCreateSSLContextFIPSModeEnabled( + X509KeyType caKeyType, X509KeyType certKeyType, String keyPassword, Integer paramIndex) + throws Exception { + init(caKeyType, certKeyType, keyPassword, paramIndex); + System.setProperty(FIPS_MODE_PROPERTY, Boolean.TRUE.toString()); + SSLContext sslContext = x509Util.getDefaultSSLContext(); + assertEquals(TLS_1_2, sslContext.getProtocol()); + assertArrayEquals(new String[]{TLS_1_2}, sslContext.getDefaultSSLParameters().getProtocols()); + } + @ParameterizedTest @MethodSource("data") @Timeout(value = 5) diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java index ed5dea56cf2..f576ad81b12 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java @@ -48,6 +48,8 @@ import org.apache.zookeeper.common.ClientX509Util; import org.apache.zookeeper.common.QuorumX509Util; import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509Util; +import org.apache.zookeeper.common.ZKConfig; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Id; import org.apache.zookeeper.server.NettyServerCnxnFactory; @@ -281,7 +283,8 @@ private void setupTLS() throws Exception { System.setProperty("zookeeper.admin.needClientAuth", "true"); // create SSLContext - final SSLContext sslContext = SSLContext.getInstance(ClientX509Util.DEFAULT_PROTOCOL); + String defaultTlsProtocol = X509Util.defaultTlsProtocol(new ZKConfig()); + final SSLContext sslContext = SSLContext.getInstance(defaultTlsProtocol); final X509AuthenticationProvider authProvider = (X509AuthenticationProvider) ProviderRegistry.getProvider("x509"); if (authProvider == null) { throw new X509Exception.SSLContextException("Could not create SSLContext with x509 auth provider");