diff options
3 files changed, 161 insertions, 8 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/App.java b/dozentenmodul/src/main/java/org/openslx/dozmod/App.java index e6e272da..f67acaba 100755 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/App.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/App.java @@ -15,6 +15,8 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.zip.Deflater; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; @@ -37,6 +39,8 @@ import org.openslx.dozmod.gui.helper.I18n; import org.openslx.dozmod.gui.helper.Language; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.util.ClientVersion; +import org.openslx.dozmod.util.FallbackTrustManager; +import org.openslx.dozmod.util.OsHelper; import org.openslx.dozmod.util.ProxyConfigurator; import org.openslx.thrifthelper.ThriftManager; import org.openslx.util.AppUtil; @@ -109,7 +113,7 @@ public class App { if (org.apache.logging.log4j.core.Logger.class.cast(LogManager.getRootLogger()).getAppenders().isEmpty()) { Configurator.initialize(new DefaultConfiguration()); } - + if (args.length >= 2) { if (args[0].equals("--json")) { writeJsonUpdateFile(args[1]); @@ -146,6 +150,18 @@ public class App { AppUtil.logHeader(LOGGER, Branding.getApplicationName(), App.class.getPackage().getImplementationVersion()); LOGGER.info("Starting logging to " + logFilePath); + if (OsHelper.isWindows()) { + // On Windows 10+, use system store in addition to the Java one + LOGGER.info("Installing Fallback X509 truster"); + try { + SSLContext sslContext = FallbackTrustManager.getSSLContext(); + SSLContext.setDefault(sslContext); + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + } catch (Exception e) { + LOGGER.warn("Cannot use fallback SSL context with system store", e); + } + } + // Setting the locale if (!setPreferredLanguage()) { // Detect operating system language diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/FallbackTrustManager.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/FallbackTrustManager.java new file mode 100644 index 00000000..1fbdb88f --- /dev/null +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/FallbackTrustManager.java @@ -0,0 +1,122 @@ +package org.openslx.dozmod.util; + +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class FallbackTrustManager { + + private final static Logger LOGGER = LogManager.getLogger(FallbackTrustManager.class); + + private static SSLContext sslContext = null; + + private static FallbackX509TrustManager delegatingTrustManager; + + static { + try { + // --- Load Java default trust store (cacerts) --- + String javaHome = System.getProperty("java.home"); + String cacertsPath = javaHome + "/lib/security/cacerts"; + char[] password = "changeit".toCharArray(); + + KeyStore javaTrustStore = KeyStore.getInstance("JKS"); + try (FileInputStream fis = new FileInputStream(cacertsPath)) { + javaTrustStore.load(fis, password); + } + + TrustManagerFactory javaTMF = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + javaTMF.init(javaTrustStore); + LOGGER.info("Java entries: " + javaTrustStore.size()); + X509TrustManager javaTrustManager = getX509TrustManager(javaTMF); + + // --- Load Windows root store --- + KeyStore windowsRoot = KeyStore.getInstance("Windows-ROOT"); + windowsRoot.load(null, null); + + TrustManagerFactory windowsTMF = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + windowsTMF.init(windowsRoot); + LOGGER.info("Windows entries: " + windowsRoot.size()); + X509TrustManager windowsTrustManager = getX509TrustManager(windowsTMF); + + // --- Combine using delegating trust manager --- + delegatingTrustManager = new FallbackX509TrustManager( + javaTrustManager, windowsTrustManager); + + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] { delegatingTrustManager }, null); + } catch (Exception e) { + } + } + + public static TrustManager getTrustManager() { + return delegatingTrustManager; + } + + public static SSLContext getSSLContext() { + return sslContext; + } + + // Extract the first X509TrustManager from the factory + private static X509TrustManager getX509TrustManager(TrustManagerFactory tmf) throws Exception { + for (TrustManager tm : tmf.getTrustManagers()) { + if (tm instanceof X509TrustManager) { + return (X509TrustManager) tm; + } + } + throw new IllegalStateException("No X509TrustManager found"); + } + + // Delegating trust manager implementation + public static class FallbackX509TrustManager implements X509TrustManager { + private final X509TrustManager primary; + private final X509TrustManager fallback; + + public FallbackX509TrustManager(X509TrustManager primary, X509TrustManager fallback) { + this.primary = primary; + this.fallback = fallback; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + try { + primary.checkClientTrusted(chain, authType); + } catch (java.security.cert.CertificateException e) { + LOGGER.warn("Using fallback client truster"); + fallback.checkClientTrusted(chain, authType); + } + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + try { + primary.checkServerTrusted(chain, authType); + } catch (java.security.cert.CertificateException e) { + LOGGER.warn("Using fallback server truster"); + fallback.checkServerTrusted(chain, authType); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + X509Certificate[] primaryIssuers = primary.getAcceptedIssuers(); + X509Certificate[] fallbackIssuers = fallback.getAcceptedIssuers(); + X509Certificate[] combined = new X509Certificate[primaryIssuers.length + fallbackIssuers.length]; + System.arraycopy(primaryIssuers, 0, combined, 0, primaryIssuers.length); + System.arraycopy(fallbackIssuers, 0, combined, primaryIssuers.length, fallbackIssuers.length); + return combined; + } + } + +} diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java index 9a38852b..a1dc0dbc 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.config.ConnectionConfig; @@ -80,7 +81,7 @@ public class ProxyConfigurator { } else { thriftCtx = SSLContext.getInstance("TLSv1.2"); } - thriftCtx.init(null, null, null); + thriftCtx.init(null, new TrustManager[] { FallbackTrustManager.getTrustManager() }, null); } catch (NoSuchAlgorithmException | KeyManagementException e) { LOGGER.warn("Error creating default SSL context for thrift", e); } @@ -95,7 +96,7 @@ public class ProxyConfigurator { MasterServer.Client masterClient; try { ctx = SSLContext.getInstance(tls[0].id); - ctx.init(null, null, null); + ctx.init(null, new TrustManager[] { FallbackTrustManager.getTrustManager() }, null); masterClient = ThriftManager.getNewMasterClient(ctx, App.getMasterServerAddress(), App.THRIFT_SSL_PORT, 4000); @@ -219,22 +220,35 @@ public class ProxyConfigurator { } private static HttpClientBuilder createDefaultBuilder() { - return HttpClientBuilder.create() + SSLConnectionSocketFactoryBuilder factoryBuilder = SSLConnectionSocketFactoryBuilder.create(); + try { + factoryBuilder.setSslContext(SSLContext.getDefault()); + } catch (Exception e) { + LOGGER.warn("Cannot set Ssl Context on slx builder", e); + } + HttpClientBuilder builder = HttpClientBuilder.create() .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(factoryBuilder.build()) .setDefaultConnectionConfig(ConnectionConfig.custom() .setConnectTimeout(ProxyConfigurator.TIMEOUT_CONNECT) .setSocketTimeout(ProxyConfigurator.TIMEOUT_SOCKET) .build()) .setMaxConnPerRoute(4) .build()); + return builder; } private static HttpClientBuilder createSlxBuilder(TLS[] tlsVersions) { - return HttpClientBuilder.create() + SSLConnectionSocketFactoryBuilder factoryBuilder = SSLConnectionSocketFactoryBuilder.create() + .setTlsVersions(tlsVersions); + try { + factoryBuilder.setSslContext(SSLContext.getDefault()); + } catch (Exception e) { + LOGGER.warn("Cannot set Ssl Context on slx builder", e); + } + HttpClientBuilder builder = HttpClientBuilder.create() .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() - .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create() - .setTlsVersions(tlsVersions) - .build()) + .setSSLSocketFactory(factoryBuilder.build()) .setDefaultTlsConfig(TlsConfig.custom() .setSupportedProtocols(tlsVersions) .build()) @@ -244,6 +258,7 @@ public class ProxyConfigurator { .build()) .setMaxConnPerRoute(4) .build()); + return builder; } private static boolean testHttpsMaster(CloseableHttpClient client) { |
