From 00dd77b3467a7612aa4bb77a0cfa76ffd3e2dda5 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 9 Mar 2020 13:39:19 +0100 Subject: [PATCH] Try to guess the default truststore and path Tested with OpenJDK 8 and 11. The 'JKS' fallback is for OpenJDK 11. --- .../smack/AbstractXMPPConnection.java | 23 +++++++++++++++- .../org/jivesoftware/smack/util/TLSUtils.java | 26 ++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 1402e3738..0e13c28c7 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -2304,7 +2304,28 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { ks = null; } } else { - ks.load(null, null); + InputStream stream = TLSUtils.getDefaultTruststoreStreamIfPossible(); + try { + // Note that PKCS12 keystores need a password one some Java platforms. Hence we try the famous + // 'changeit' here. See https://bugs.openjdk.java.net/browse/JDK-8194702 + char[] password = "changeit".toCharArray(); + try { + ks.load(stream, password); + } finally { + stream.close(); + } + } catch (IOException e) { + LOGGER.log(Level.FINE, "KeyStore load() threw, attempting 'jks' fallback", e); + + ks = KeyStore.getInstance("jks"); + // Open the stream again, so that we read it from the beginning. + stream = TLSUtils.getDefaultTruststoreStreamIfPossible(); + try { + ks.load(stream, null); + } finally { + stream.close(); + } + } } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/TLSUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/TLSUtils.java index 807ffd958..97dc8597f 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/TLSUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/TLSUtils.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014-2016 Florian Schmaus + * Copyright 2014-2020 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,9 @@ */ package org.jivesoftware.smack.util; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -29,6 +32,8 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; @@ -45,6 +50,8 @@ import org.jivesoftware.smack.SmackException.SecurityNotPossibleException; public class TLSUtils { + private static final Logger LOGGER = Logger.getLogger(TLSUtils.class.getName()); + public static final String SSL = "SSL"; public static final String TLS = "TLS"; public static final String PROTO_SSL3 = SSL + "v3"; @@ -261,4 +268,21 @@ public class TLSUtils { } throw new AssertionError("No trust manager for the default algorithm " + defaultAlgorithm + " found"); } + + private static final File DEFAULT_TRUSTSTORE_PATH; + + static { + String javaHome = System.getProperty("java.home"); + String defaultTruststorePath = javaHome + File.separator + "lib" + File.separator + "security" + File.separator + "cacerts"; + DEFAULT_TRUSTSTORE_PATH = new File(defaultTruststorePath); + } + + public static FileInputStream getDefaultTruststoreStreamIfPossible() { + try { + return new FileInputStream(DEFAULT_TRUSTSTORE_PATH); + } catch (FileNotFoundException e) { + LOGGER.log(Level.WARNING, "Could not open default truststore at " + DEFAULT_TRUSTSTORE_PATH, e); + return null; + } + } }