From f9aa7e46d47b494aca6ecef9fb8cf8a0944f0c89 Mon Sep 17 00:00:00 2001 From: stianst Date: Wed, 23 Sep 2026 09:29:41 +0200 Subject: [PATCH 1/2] Upgrade BouncyCastle FIPS Closes #52974 Closes #52972 Signed-off-by: stianst --- docs/guides/server/fips.adoc | 2 +- pom.xml | 8 ++++---- .../test/java/org/keycloak/it/cli/dist/FipsDistTest.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/guides/server/fips.adoc b/docs/guides/server/fips.adoc index 50c24b843d11..0e4da0aae9b3 100644 --- a/docs/guides/server/fips.adoc +++ b/docs/guides/server/fips.adoc @@ -126,7 +126,7 @@ When starting the server, you can check that the startup log contains `KC` provi [source] ---- -FIPS1402Provider created: KC(BCFIPS version 2.0102 Approved Mode, FIPS-JVM: enabled) +FIPS1402Provider created: KC(BCFIPS version 2.0103 Approved Mode, FIPS-JVM: enabled) ---- === Cryptography restrictions in strict mode diff --git a/pom.xml b/pom.xml index 2e28fd817238..108b2fa2afb8 100644 --- a/pom.xml +++ b/pom.xml @@ -74,10 +74,10 @@ 1.5.1.Final - 2.1.10 - 2.1.2 - 2.1.22 - 2.1.5 + 2.1.13 + 2.1.3 + 2.1.25 + 2.1.8 2.1.3 2.4.240 diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java index 771c21915edf..5d77f8b5c7d4 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java @@ -36,7 +36,7 @@ @Tag(DistributionTest.SLOW) public class FipsDistTest { - private static final String BCFIPS_VERSION = "BCFIPS version 2.0102"; + private static final String BCFIPS_VERSION = "BCFIPS version 2.0103"; @Test void testFipsNonApprovedMode(KeycloakRunner runner) { From c78d1202cab5802abe8d0deeef4e2cc5e5627bf4 Mon Sep 17 00:00:00 2001 From: Stefan Guilhen Date: Wed, 23 Sep 2026 10:29:58 -0300 Subject: [PATCH 2/2] Add SNIAwareSSLSocketFactory wrapper that intercepts socket creation and sets the server hostname via SSLParameters.setServerNames(). Signed-off-by: Stefan Guilhen --- .../idm/store/ldap/LDAPContextManager.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/idm/store/ldap/LDAPContextManager.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/idm/store/ldap/LDAPContextManager.java index fabdf841bafa..36ba5d69d246 100644 --- a/federation/ldap/src/main/java/org/keycloak/storage/ldap/idm/store/ldap/LDAPContextManager.java +++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/idm/store/ldap/LDAPContextManager.java @@ -106,6 +106,11 @@ private void createLdapContext() throws NamingException { sslSocketFactory = provider.getSSLSocketFactory(); } + // Wrap factory to ensure SNI hostname is set for endpoint verification + if (sslSocketFactory != null) { + sslSocketFactory = new SNIAwareSSLSocketFactory(sslSocketFactory); + } + tlsResponse = startTLS(ldapContext, sslSocketFactory); // Exception should be already thrown by LDAPContextManager.startTLS if "startTLS" could not be established, but rather do some additional check @@ -292,6 +297,71 @@ public static Hashtable getNonAuthConnectionProperties(LDAPConfi return new Hashtable<>(env); } + private static class SNIAwareSSLSocketFactory extends javax.net.ssl.SSLSocketFactory { + private final javax.net.ssl.SSLSocketFactory delegate; + + SNIAwareSSLSocketFactory(javax.net.ssl.SSLSocketFactory delegate) { + this.delegate = delegate; + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public java.net.Socket createSocket(java.net.Socket socket, String host, int port, boolean autoClose) throws java.io.IOException { + return setSNI(delegate.createSocket(socket, host, port, autoClose), host); + } + + @Override + public java.net.Socket createSocket(String host, int port) throws java.io.IOException { + return setSNI(delegate.createSocket(host, port), host); + } + + @Override + public java.net.Socket createSocket(String host, int port, java.net.InetAddress localHost, int localPort) throws java.io.IOException { + return setSNI(delegate.createSocket(host, port, localHost, localPort), host); + } + + @Override + public java.net.Socket createSocket(java.net.InetAddress address, int port) throws java.io.IOException { + return delegate.createSocket(address, port); + } + + @Override + public java.net.Socket createSocket(java.net.InetAddress address, int port, java.net.InetAddress localAddress, int localPort) throws java.io.IOException { + return delegate.createSocket(address, port, localAddress, localPort); + } + + @Override + public java.net.Socket createSocket() throws java.io.IOException { + return delegate.createSocket(); + } + + private static java.net.Socket setSNI(java.net.Socket socket, String hostname) { + if (hostname != null && socket instanceof javax.net.ssl.SSLSocket) { + try { + javax.net.ssl.SSLSocket sslSocket = (javax.net.ssl.SSLSocket) socket; + javax.net.ssl.SSLParameters params = sslSocket.getSSLParameters(); + if (params == null) { + params = new javax.net.ssl.SSLParameters(); + } + params.setServerNames(java.util.Collections.singletonList(new javax.net.ssl.SNIHostName(hostname))); + sslSocket.setSSLParameters(params); + } catch (Exception e) { + logger.debugf("Failed to set SNI hostname '%s' for LDAP TLS: %s", hostname, e.getMessage()); + } + } + return socket; + } + } + @Override public void close() { if (tlsResponse != null) {