This is an automated email from the ASF dual-hosted git repository.
szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git
The following commit(s) were added to refs/heads/master by this push:
new bceb3c209 RATIS-2602. Pass CipherSuiteFilter to the TlsConf. (#1517)
bceb3c209 is described below
commit bceb3c20929dabe3041b5793a53d3a7881278f61
Author: Haonan <[email protected]>
AuthorDate: Tue Jul 14 11:36:01 2026 +0800
RATIS-2602. Pass CipherSuiteFilter to the TlsConf. (#1517)
---
.../java/org/apache/ratis/security/TlsConf.java | 25 +++++++++++++++++
.../java/org/apache/ratis/util/NettyUtils.java | 8 ++----
.../java/org/apache/ratis/grpc/GrpcTlsConfig.java | 7 +++++
.../main/java/org/apache/ratis/grpc/GrpcUtil.java | 3 +--
.../org/apache/ratis/grpc/TestGrpcTlsConfig.java | 31 ++++++++++++++++++++++
.../apache/ratis/netty/TestTlsConfWithNetty.java | 19 +++++++++++++
6 files changed, 85 insertions(+), 8 deletions(-)
diff --git a/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
b/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
index b44212459..1fde322e3 100644
--- a/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
+++ b/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
@@ -17,7 +17,9 @@
*/
package org.apache.ratis.security;
+import org.apache.ratis.thirdparty.io.netty.handler.ssl.CipherSuiteFilter;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
+import
org.apache.ratis.thirdparty.io.netty.handler.ssl.SupportedCipherSuiteFilter;
import org.apache.ratis.util.JavaUtils;
import org.apache.ratis.util.Preconditions;
@@ -178,6 +180,7 @@ public class TlsConf {
private final String jsseProviderName;
private final List<String> protocols;
private final List<String> cipherSuites;
+ private final CipherSuiteFilter cipherSuiteFilter;
protected TlsConf(Builder b) {
final String buildName = b.buildName();
@@ -190,6 +193,7 @@ public class TlsConf {
this.jsseProviderName = b.jsseProviderName;
this.protocols = copy(b.protocols);
this.cipherSuites = copy(b.cipherSuites);
+ this.cipherSuiteFilter = b.cipherSuiteFilter;
}
/** @return the key manager configuration. */
@@ -223,6 +227,14 @@ public class TlsConf {
return copy(cipherSuites);
}
+ /**
+ * @return the filter applied to configured cipher suites. The default is
+ * {@link SupportedCipherSuiteFilter#INSTANCE}.
+ */
+ public CipherSuiteFilter getCipherSuiteFilter() {
+ return cipherSuiteFilter;
+ }
+
@Override
public String toString() {
return name;
@@ -253,6 +265,7 @@ public class TlsConf {
private String jsseProviderName;
private List<String> protocols;
private List<String> cipherSuites;
+ private CipherSuiteFilter cipherSuiteFilter =
SupportedCipherSuiteFilter.INSTANCE;
public Builder setName(String name) {
this.name = name;
@@ -319,6 +332,18 @@ public class TlsConf {
return this;
}
+ /**
+ * Set the filter applied to configured cipher suites.
+ *
+ * <p>A pass-through filter such as {@code IdentityCipherSuiteFilter}
preserves provider-specific
+ * suites that may be absent from Netty's supported set. It does not make
an unsupported suite
+ * valid; validation may instead fail when the TLS engine is initialized
or during the handshake.
+ */
+ public Builder setCipherSuiteFilter(CipherSuiteFilter cipherSuiteFilter) {
+ this.cipherSuiteFilter = Objects.requireNonNull(cipherSuiteFilter,
"cipherSuiteFilter == null");
+ return this;
+ }
+
private boolean isMutualTls() {
return mutualTls;
}
diff --git a/ratis-common/src/main/java/org/apache/ratis/util/NettyUtils.java
b/ratis-common/src/main/java/org/apache/ratis/util/NettyUtils.java
index c7ba9d3bb..aa6738bb8 100644
--- a/ratis-common/src/main/java/org/apache/ratis/util/NettyUtils.java
+++ b/ratis-common/src/main/java/org/apache/ratis/util/NettyUtils.java
@@ -37,7 +37,6 @@ import
org.apache.ratis.thirdparty.io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContext;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContextBuilder;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
-import
org.apache.ratis.thirdparty.io.netty.handler.ssl.SupportedCipherSuiteFilter;
import org.apache.ratis.thirdparty.io.netty.util.concurrent.Future;
import org.apache.ratis.thirdparty.io.netty.util.concurrent.ScheduledFuture;
import org.slf4j.Logger;
@@ -197,10 +196,7 @@ public interface NettyUtils {
* {@link TlsConf} to the builder, so that the Netty DataStream transport
honours the same
* configuration instead of falling back on the provider defaults.
*
- * <p>Unlike the gRPC path ({@code GrpcUtil.configureSslContextBuilder})
this uses
- * {@link SupportedCipherSuiteFilter}, which intersects the requested cipher
suites with the
- * ones actually supported by the negotiated provider/engine, rather than
passing them through
- * verbatim.
+ * <p>The cipher suite filter is supplied by {@link
TlsConf#getCipherSuiteFilter()}.
*/
static SslContextBuilder configureSslContextBuilder(SslContextBuilder b,
TlsConf tlsConf) {
final SslProvider sslProvider = tlsConf.getSslProvider();
@@ -217,7 +213,7 @@ public interface NettyUtils {
}
final List<String> cipherSuites = tlsConf.getCipherSuites();
if (cipherSuites != null && !cipherSuites.isEmpty()) {
- b.ciphers(cipherSuites, SupportedCipherSuiteFilter.INSTANCE);
+ b.ciphers(cipherSuites, tlsConf.getCipherSuiteFilter());
}
return b;
}
diff --git a/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
b/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
index c6b8dce59..c38cb0671 100644
--- a/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
+++ b/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
@@ -18,6 +18,7 @@
package org.apache.ratis.grpc;
import org.apache.ratis.security.TlsConf;
+import org.apache.ratis.thirdparty.io.netty.handler.ssl.CipherSuiteFilter;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
import javax.net.ssl.KeyManager;
@@ -217,6 +218,12 @@ public class GrpcTlsConfig extends TlsConf {
return this;
}
+ @Override
+ public Builder setCipherSuiteFilter(CipherSuiteFilter cipherSuiteFilter) {
+ super.setCipherSuiteFilter(cipherSuiteFilter);
+ return this;
+ }
+
@Override
public GrpcTlsConfig build() {
return new GrpcTlsConfig(this, false);
diff --git a/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcUtil.java
b/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcUtil.java
index 3abbb1832..b1456480f 100644
--- a/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcUtil.java
+++ b/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcUtil.java
@@ -36,7 +36,6 @@ import
org.apache.ratis.thirdparty.io.netty.handler.ssl.ClientAuth;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContext;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContextBuilder;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
-import
org.apache.ratis.thirdparty.io.netty.handler.ssl.SupportedCipherSuiteFilter;
import org.apache.ratis.util.IOUtils;
import org.apache.ratis.util.JavaUtils;
import org.apache.ratis.util.LogUtils;
@@ -339,7 +338,7 @@ public interface GrpcUtil {
}
final List<String> cipherSuites = tlsConf.getCipherSuites();
if (cipherSuites != null && !cipherSuites.isEmpty()) {
- b.ciphers(cipherSuites, SupportedCipherSuiteFilter.INSTANCE);
+ b.ciphers(cipherSuites, tlsConf.getCipherSuiteFilter());
}
return b;
}
diff --git
a/ratis-grpc/src/test/java/org/apache/ratis/grpc/TestGrpcTlsConfig.java
b/ratis-grpc/src/test/java/org/apache/ratis/grpc/TestGrpcTlsConfig.java
index d3c6be8e2..1403dc97f 100644
--- a/ratis-grpc/src/test/java/org/apache/ratis/grpc/TestGrpcTlsConfig.java
+++ b/ratis-grpc/src/test/java/org/apache/ratis/grpc/TestGrpcTlsConfig.java
@@ -17,7 +17,11 @@
*/
package org.apache.ratis.grpc;
+import org.apache.ratis.thirdparty.io.netty.handler.ssl.CipherSuiteFilter;
+import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContext;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContextBuilder;
+import
org.apache.ratis.thirdparty.io.netty.handler.ssl.SupportedCipherSuiteFilter;
+import org.apache.ratis.thirdparty.io.netty.util.ReferenceCountUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -26,6 +30,7 @@ import java.security.Provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
public class TestGrpcTlsConfig {
@Test
@@ -48,6 +53,32 @@ public class TestGrpcTlsConfig {
() -> conf.getCipherSuites().add("TLS_AES_256_GCM_SHA384"));
}
+ @Test
+ public void testCipherSuiteFilterIsApplied() throws SSLException {
+ Assertions.assertSame(SupportedCipherSuiteFilter.INSTANCE,
+ GrpcTlsConfig.newBuilder().build().getCipherSuiteFilter());
+
+ final AtomicBoolean invoked = new AtomicBoolean();
+ final CipherSuiteFilter filter = (ciphers, defaultCiphers,
supportedCiphers) -> {
+ invoked.set(true);
+ return SupportedCipherSuiteFilter.INSTANCE
+ .filterCipherSuites(null, defaultCiphers, supportedCiphers);
+ };
+ final GrpcTlsConfig conf = GrpcTlsConfig.newBuilder()
+ .setCipherSuites("TLS_TEST_CIPHER")
+ .setCipherSuiteFilter(filter)
+ .build();
+
+ final SslContext context = GrpcUtil.configureSslContextBuilder(
+ SslContextBuilder.forClient(), conf, null).build();
+ try {
+ Assertions.assertTrue(invoked.get());
+ Assertions.assertSame(filter, conf.getCipherSuiteFilter());
+ } finally {
+ ReferenceCountUtil.release(context);
+ }
+ }
+
@Test
public void testUnknownJsseProviderUsesGenericJdkConfiguration() {
final SslContextBuilder builder = GrpcUtil.configureJsseProvider(
diff --git
a/ratis-test/src/test/java/org/apache/ratis/netty/TestTlsConfWithNetty.java
b/ratis-test/src/test/java/org/apache/ratis/netty/TestTlsConfWithNetty.java
index b74fa92ce..ca913d7bc 100644
--- a/ratis-test/src/test/java/org/apache/ratis/netty/TestTlsConfWithNetty.java
+++ b/ratis-test/src/test/java/org/apache/ratis/netty/TestTlsConfWithNetty.java
@@ -36,6 +36,7 @@ import
org.apache.ratis.thirdparty.io.netty.channel.socket.SocketChannel;
import
org.apache.ratis.thirdparty.io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.ratis.thirdparty.io.netty.handler.logging.LogLevel;
import org.apache.ratis.thirdparty.io.netty.handler.logging.LoggingHandler;
+import
org.apache.ratis.thirdparty.io.netty.handler.ssl.IdentityCipherSuiteFilter;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContext;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
import org.apache.ratis.util.JavaUtils;
@@ -144,6 +145,24 @@ public class TestTlsConfWithNetty {
Assertions.assertEquals(Collections.singletonList(VALID_CIPHER),
ctx.cipherSuites());
}
+ /** The configured cipher suite filter must be passed to the Netty {@link
SslContext}. See RATIS-2602. */
+ @Test
+ public void testIdentityCipherSuiteFilterIsApplied() {
+ final List<String> ciphers = Arrays.asList(UNSUPPORTED_CIPHER,
VALID_CIPHER);
+ final TlsConf conf = TlsConf.newBuilder()
+ .setName("server")
+ .setPrivateKey(new
TlsConf.PrivateKeyConf(SecurityTestUtils.getResource("ssl/server.pem")))
+ .setKeyCertificates(new
TlsConf.CertificatesConf(SecurityTestUtils.getResource("ssl/server.crt")))
+ .setSslProvider(SslProvider.JDK)
+ .setProtocols(TLS_1_2)
+ .setCipherSuites(ciphers)
+ .setCipherSuiteFilter(IdentityCipherSuiteFilter.INSTANCE)
+ .build();
+
+ final SslContext ctx = NettyUtils.buildSslContextForServer(conf);
+ Assertions.assertEquals(ciphers, ctx.cipherSuites());
+ }
+
/**
* End-to-end handshake with explicit protocol and cipher configuration,
including an unsupported
* cipher that must be filtered out without breaking the handshake.