[РЕШЕНО] TLS 1.2 – SSLHandshakeException: Удаленный хост закрыл соединение во время установления связи

SSLHandshakeException появляются в журналах, когда происходит какая-то ошибка при проверке сертификата, установленного на клиентской машине, с сертификатом на серверной машине. В этой статье мы узнаем, как исправить это, если вы используете библиотеку Apache HttpClient для создания HttpClient для подключения к URL-адресам, защищенным SSL/TLS.

1. Проблема

Журналы исключений будут выглядеть следующим образом.

 Причина: javax.net.ssl.SSLHandshakeException: Удаленный хост закрыл соединение во время установления связив sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:980)......Причина: java.io.EOFException: SSL-пир завершил работу некорректнов sun.security.ssl.InputRecord.read(InputRecord.java:505)......

Я уже опубликовал исправление кода для обхода сопоставления SSL в предыдущем посте.

К сожалению, это исправление работает в протоколах TLS и TLS 1.1. Оно не работает в протоколе TLS 1.2. Так что в конечном итоге вам в любом случае нужно исправить проблему с сертификатом. Для этого есть исправление «только без кода».

2. Решение

Теперь есть два способа, вы можете использовать импортированный сертификат с сервера. Либо добавить сертификат в хранилище JDK cacerts; либо передать информацию о сертификате в аргументах JVM.

2.1. Импорт сертификата в JDK cacert Store

Импортируйте сертификат с сервера.

Используйте данную команду для добавления сертификата в хранилище JDK.(Удалите символы новой строки).

keytool -import-noprompt-trustcacerts-alias MAVEN-ROOT-file C:/Users/Lokesh/keys/cert/maven.cer-keystore "C:/Program Files(x86)/Java/jdk8/jre/lib/security/cacerts"-storepass changeit

Теперь создайте HttpClient, как указано ниже:

public HttpClient createTlsV2HttpClient() throws KeyManagementException,UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {SSLContext sslContext = SSLContext.getInstance("TLSv1.2");SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", f).build();PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(f).setConnectionManager(cm).build();return client;}

Обратите внимание на код: SSLContext.getInstance(«TLSv1.2»). Этот код выбирает сертификаты, добавленные в хранилище JDK cacert. Так что запомните его.

2.2. Передача информации о сертификате в аргументах JVM

Импортируйте сертификат с сервера.

Добавьте аргументы JVM при запуске сервера. Измените значения параметров в соответствии с вашим приложением.

-Djavax.net.ssl.keyStore="C:/Users/Lokesh\keys\maven.jks"-Djavax.net.ssl.keyStorePassword="test"-Djavax.net.ssl.trustStore="C:/Users/Lokesh\keys\maven.jks"-Djavax.net.ssl.trustStorePassword="test"

Теперь создайте HTTP-клиент, как указано ниже:

public HttpClient createTlsV2HttpClient() throws KeyManagementException,UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {SSLContext sslContext = SSLContexts.createSystemDefault();SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", f).build();PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(f).setConnectionManager(cm).build();return client;}

Обратите внимание на код: SSLContext.createSystemDefault(). Этот код выбирает сертификаты, переданные как аргументы JVM. Опять же, запишите его.

3. Заключение

  • Используйте SSLContext.getInstance(«TLSv1.2») при добавлении сертификата в хранилище JDK cacert.
  • Используйте SSLContext.createSystemDefault(), когда информация SSL передается как аргумент JVM.

Пишите мне свои вопросы в комментариях.

Прокрутить вверх