В моем приложении есть личное хранилище ключей, содержащее доверенные самозаверяющие сертификаты для использования в локальной сети, например mykeystore.jks
. Я хочу иметь возможность подключаться к общедоступным сайтам (например, google.com), а также к сайтам в моей локальной сети, используя самозаверяющие сертификаты, которые были предоставлены локально.
Проблема здесь в том, что, когда я подключаюсь к https://google.com, создание пути не удается, потому что установка моего собственного хранилища ключей переопределяет хранилище ключей по умолчанию, содержащее корневые центры сертификации, связанные с JRE, сообщая об исключении
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Однако, если я импортирую сертификат CA в свое собственное хранилище ключей (mykeystore.jks
), он работает нормально. Есть ли способ поддержать и то, и другое?
Для этого у меня есть собственный TrustManger,
public class CustomX509TrustManager implements X509TrustManager {
X509TrustManager defaultTrustManager;
public MyX509TrustManager(KeyStore keystore) {
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustMgrFactory.init(keystore);
TrustManager trustManagers[] = trustMgrFactory.getTrustManagers();
for (int i = 0; i < trustManagers.length; i++) {
if (trustManagers[i] instanceof X509TrustManager) {
defaultTrustManager = (X509TrustManager) trustManagers[i];
return;
}
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
/* Handle untrusted certificates */
}
}
}
Затем я инициализирую SSLContext,
TrustManager[] trustManagers =
new TrustManager[] { new CustomX509TrustManager(keystore) };
SSLContext customSSLContext =
SSLContext.getInstance("TLS");
customSSLContext.init(null, trustManagers, null);
и установите фабрику сокетов,
HttpsURLConnection.setDefaultSSLSocketFactory(customSSLContext.getSocketFactory());
Основная программа,
URL targetServer = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection();
Если я не установлю собственные доверительные менеджеры, он будет нормально подключаться к https://google.com. Как мне получить «диспетчера доверия по умолчанию», который указывает на хранилище ключей по умолчанию?