From 7dc12a37e41fd5ab8c224bf01192adfa31395507 Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 12 Jun 2026 00:29:46 +0000 Subject: [PATCH] Use X509ExtendedTrustManager to avoid JDK AlgorithmChecker constraints Netty 4.2.15 fixed CVE-2026-50010 by removing the silent wrapping of plain X509TrustManager in X509ExtendedTrustManager. When a plain X509TrustManager is used, the JDK wraps it in AbstractTrustManagerWrapper and runs TrustManagerImpl.checkTrusted() with AlgorithmChecker before calling the custom trust manager. This caused client certificates signed with SHA3-512withECDSA to be rejected even though they are not explicitly blacklisted in java.security, because the JDK's internal PKIX validator applies stricter constraints. By making our custom trust managers implement X509ExtendedTrustManager directly, the JDK calls the 3-arg methods directly and bypasses its internal TrustManagerImpl, restoring the pre-4.2.15 behavior where only our custom PKIX validation runs. Files changed: - rbcs-common/RBCS.kt: getTrustManager() returns X509ExtendedTrustManager - rbcs-client/RemoteBuildCacheClient.kt: trust-all manager uses X509ExtendedTrustManager --- .../rbcs/client/RemoteBuildCacheClient.kt | 15 ++++++++++- .../kotlin/net/woggioni/rbcs/common/RBCS.kt | 25 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/rbcs-client/src/main/kotlin/net/woggioni/rbcs/client/RemoteBuildCacheClient.kt b/rbcs-client/src/main/kotlin/net/woggioni/rbcs/client/RemoteBuildCacheClient.kt index 4abed6e..9f5cfe8 100644 --- a/rbcs-client/src/main/kotlin/net/woggioni/rbcs/client/RemoteBuildCacheClient.kt +++ b/rbcs-client/src/main/kotlin/net/woggioni/rbcs/client/RemoteBuildCacheClient.kt @@ -10,6 +10,7 @@ import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException import java.util.concurrent.atomic.AtomicInteger import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509ExtendedTrustManager import javax.net.ssl.X509TrustManager import kotlin.random.Random import io.netty.util.concurrent.Future as NettyFuture @@ -74,13 +75,25 @@ class RemoteBuildCacheClient(private val profile: Configuration.Profile) : AutoC ) profile.tlsTruststore?.let { trustStore -> if (!trustStore.verifyServerCertificate) { - trustManager(object : X509TrustManager { + trustManager(object : X509ExtendedTrustManager() { override fun checkClientTrusted(certChain: Array, p1: String?) { } + override fun checkClientTrusted(certChain: Array, p1: String?, socket: java.net.Socket) { + } + + override fun checkClientTrusted(certChain: Array, p1: String?, engine: javax.net.ssl.SSLEngine) { + } + override fun checkServerTrusted(certChain: Array, p1: String?) { } + override fun checkServerTrusted(certChain: Array, p1: String?, socket: java.net.Socket) { + } + + override fun checkServerTrusted(certChain: Array, p1: String?, engine: javax.net.ssl.SSLEngine) { + } + override fun getAcceptedIssuers() = null }) } else { diff --git a/rbcs-common/src/main/kotlin/net/woggioni/rbcs/common/RBCS.kt b/rbcs-common/src/main/kotlin/net/woggioni/rbcs/common/RBCS.kt index 342820b..4815304 100644 --- a/rbcs-common/src/main/kotlin/net/woggioni/rbcs/common/RBCS.kt +++ b/rbcs-common/src/main/kotlin/net/woggioni/rbcs/common/RBCS.kt @@ -19,6 +19,7 @@ import java.security.cert.X509Certificate import java.util.EnumSet import java.util.ServiceLoader import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509ExtendedTrustManager import javax.net.ssl.X509TrustManager import net.woggioni.jwo.JWO import net.woggioni.jwo.Tuple2 @@ -124,7 +125,7 @@ object RBCS { return keystore } - fun getTrustManager(trustStore: KeyStore?, certificateRevocationEnabled: Boolean): X509TrustManager { + fun getTrustManager(trustStore: KeyStore?, certificateRevocationEnabled: Boolean): X509ExtendedTrustManager { return if (trustStore != null) { val certificateFactory = CertificateFactory.getInstance("X.509") val validator = CertPathValidator.getInstance("PKIX").apply { @@ -136,7 +137,7 @@ object RBCS { val params = PKIXParameters(trustStore).apply { isRevocationEnabled = certificateRevocationEnabled } - object : X509TrustManager { + object : X509ExtendedTrustManager() { override fun checkClientTrusted(chain: Array, authType: String) { val clientCertificateChain = certificateFactory.generateCertPath(chain.toList()) try { @@ -146,10 +147,26 @@ object RBCS { } } + override fun checkClientTrusted(chain: Array, authType: String, socket: java.net.Socket) { + checkClientTrusted(chain, authType) + } + + override fun checkClientTrusted(chain: Array, authType: String, engine: javax.net.ssl.SSLEngine) { + checkClientTrusted(chain, authType) + } + override fun checkServerTrusted(chain: Array, authType: String) { throw NotImplementedError() } + override fun checkServerTrusted(chain: Array, authType: String, socket: java.net.Socket) { + checkServerTrusted(chain, authType) + } + + override fun checkServerTrusted(chain: Array, authType: String, engine: javax.net.ssl.SSLEngine) { + checkServerTrusted(chain, authType) + } + private val acceptedIssuers = trustStore.aliases().asSequence() .filter(trustStore::isCertificateEntry) .map(trustStore::getCertificate) @@ -161,8 +178,8 @@ object RBCS { } } else { val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) - trustManagerFactory.trustManagers.asSequence().filter { it is X509TrustManager } - .single() as X509TrustManager + trustManagerFactory.trustManagers.asSequence().filter { it is X509ExtendedTrustManager } + .single() as X509ExtendedTrustManager } }