Connect error javax net ssl sslhandshakeexception

[SOLVED] TLS 1.2 – SSLHandshakeException: Remote host closed connection during handshake Last Updated: January 25, 2022 SSLHandshakeException appear in logs when there is some error occur while validating the certificate installed in client machine with certificate on server machine. In this post, we will learn about fixing this if you are using Apache HttpClient […]

Содержание

  1. [SOLVED] TLS 1.2 – SSLHandshakeException: Remote host closed connection during handshake
  2. 1) Import certificate to JDK cacert store
  3. 2) Pass certificate information in JVM aruguments
  4. Summary
  5. SSLHandshake Exception Class
  6. Definition
  7. Remarks
  8. Constructors
  9. Fields
  10. Properties
  11. Methods
  12. Explicit Interface Implementations
  13. Extension Methods
  14. How to Fix javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException in Java? Example
  15. How did I solved this Problem?
  16. Сбои SSL-рукопожатия
  17. 1. Обзор
  18. 2. Терминология
  19. 3. Настройка
  20. 3.1. Создание Клиента и Сервера
  21. 3.2. Создание сертификатов на Java
  22. 4. SSL-рукопожатие
  23. 4.1. Рукопожатие в одностороннем SSL
  24. 4.2. Рукопожатие в двустороннем SSL
  25. 5. Сценарии Сбоя Рукопожатия
  26. 5.1. Отсутствует сертификат Сервера
  27. 5.2. Сертификат ненадежного Сервера
  28. 5.3. Отсутствие Сертификата Клиента
  29. 5.4. Неверные Сертификаты
  30. 5.5. Несовместимая версия SSL
  31. 5.6. Несовместимый набор шифров
  32. 6. Заключение

[SOLVED] TLS 1.2 – SSLHandshakeException: Remote host closed connection during handshake

Last Updated: January 25, 2022

SSLHandshakeException appear in logs when there is some error occur while validating the certificate installed in client machine with certificate on server machine. In this post, we will learn about fixing this if you are using Apache HttpClient library to create HttpClient to connect to SSL/TLS secured URLs.

The exception logs will look like this.

I have already posted code fix to bypass SSL matching in earlier post.

Unfortunately, that fix works in TLS and TLS 1.1 protocols. It doesn’t work in TLS 1.2 protocol. So ultimately, you need to fix the certificate issue anyway. There is ‘no code only’ fix for this.

Now there are two ways, you can utilize the imported certificate from server. Either add certificate to the JDK cacerts store; or pass certificate information in JVM aruguments.

1) Import certificate to JDK cacert store

  1. Import the certificate from server.
  2. Use given command to add the certificate to JDK store. (Remove new line characters).

Now create HTTP client as given:

Notice the code : SSLContext.getInstance(«TLSv1.2») . This code picks up the certificates added to JDK cacert store . So make a note of it.

2) Pass certificate information in JVM aruguments

  1. Import the certicate from server.
  2. Add JVM arguments while starting the server. Change the parameter values as per your application.

Now create HTTP client as given:

Notice the code : SSLContext.createSystemDefault() . This code picks up the certificates passed as JVM arguments. Again, make a note of it.

Summary

  1. Use SSLContext.getInstance(«TLSv1.2») when certificate is added to JDK cacert store.
  2. Use SSLContext.createSystemDefault() when SSL info is passed as JVM argument.

Drop me your questions in comments section.

Источник

SSLHandshake Exception Class

Definition

Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Indicates that the client and server could not negotiate the desired level of security.

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Constructors

A constructor used when creating managed representations of JNI objects; called by the runtime.

Constructs an exception reporting an error found by an SSL subsystem during handshaking.

Fields

Properties

Returns the cause of this throwable or null if the cause is nonexistent or unknown.

(Inherited from Throwable) Class (Inherited from Throwable) Handle

The handle to the underlying Android instance.

(Inherited from Throwable) JniIdentityHashCode (Inherited from Throwable) JniPeerMembers LocalizedMessage

Creates a localized description of this throwable.

(Inherited from Throwable) Message

Returns the detail message string of this throwable.

(Inherited from Throwable) PeerReference (Inherited from Throwable) StackTrace (Inherited from Throwable) ThresholdClass

This API supports the Mono for Android infrastructure and is not intended to be used directly from your code.

This API supports the Mono for Android infrastructure and is not intended to be used directly from your code.

Methods

Appends the specified exception to the exceptions that were suppressed in order to deliver this exception.

(Inherited from Throwable) Dispose() (Inherited from Throwable) Dispose(Boolean) (Inherited from Throwable) FillInStackTrace()

Fills in the execution stack trace.

(Inherited from Throwable) GetStackTrace()

Provides programmatic access to the stack trace information printed by #printStackTrace() .

(Inherited from Throwable) GetSuppressed()

Returns an array containing all of the exceptions that were suppressed, typically by the try -with-resources statement, in order to deliver this exception.

(Inherited from Throwable) InitCause(Throwable)

Initializes the cause of this throwable to the specified value.

(Inherited from Throwable) PrintStackTrace()

Prints this throwable and its backtrace to the standard error stream.

(Inherited from Throwable) PrintStackTrace(PrintStream)

Prints this throwable and its backtrace to the specified print stream.

(Inherited from Throwable) PrintStackTrace(PrintWriter)

Prints this throwable and its backtrace to the specified print writer.

(Inherited from Throwable) SetHandle(IntPtr, JniHandleOwnership)

Sets the Handle property.

(Inherited from Throwable) SetStackTrace(StackTraceElement[])

Sets the stack trace elements that will be returned by #getStackTrace() and printed by #printStackTrace() and related methods.

(Inherited from Throwable) ToString() (Inherited from Throwable) UnregisterFromRuntime() (Inherited from Throwable)

Explicit Interface Implementations

IJavaPeerable.Disposed() (Inherited from Throwable)
IJavaPeerable.DisposeUnlessReferenced() (Inherited from Throwable)
IJavaPeerable.Finalized() (Inherited from Throwable)
IJavaPeerable.JniManagedPeerState (Inherited from Throwable)
IJavaPeerable.SetJniIdentityHashCode(Int32) (Inherited from Throwable)
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) (Inherited from Throwable)
IJavaPeerable.SetPeerReference(JniObjectReference) (Inherited from Throwable)

Extension Methods

Performs an Android runtime-checked type conversion.

Источник

How to Fix javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException in Java? Example

If you are working in a Java web or enterprise application that connects to any other web server using HTTPS you might have seen the » javax.net.ssl.SSLHandshakeException» . This is one of the particular cases of that error. If you know how SSL and HTTPS work that when a Java client connects to a Java server the SSL handshake happens. In these steps server return certificates to confirm its identity, which the client validates against the root certificate he has in its truststore. If Server returns a certificate that cannot be validated against the certificates a browser or Java client holds in its truststore then it throws the «sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target».

In other words, while connecting to any website or server using SSL or HTTPS in Java, sometimes you may face a problem of «unable to find valid certification path to requested target» exception as shown below:

javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

The reason of this error is simple, certificates returned by the Server during SSL handshake are not signed by any trusted Certification Authority(CA) which are configured in your JRE’s truststore e.g Verisign, Thwate, GoDaddy, or Entrust etc.

Instead, the Server is sending a certificate that is unknown to JRE and that’s why it’s not able to validate those certifications against the private key he holds in his truststore.

If you remember, there is a subtle difference between keystore and truststore in Java. Even though, both stores certificates, keystore is used to store your credential (server or client) while truststore is used to store other credentials (Certificates from CA).

This could also happen when Server is sending certificate from other certificate authority which is not configured in JRE’s truststore i.e. some internal certificate signed by your company.

I got the exactly same error while connecting to our LDAP server using SSL from my Spring Security based Java web application. Since LDAP server was internal to the company, it was sending internally signed certificates which were not present in the Tomcat’s JRE (Java Runtime Environment).

To solve this problem you need to add certificates returned by the Server into your JRE’s truststore, which you can do by using keytool or other tools provided by your company.

How did I solved this Problem?

Nothing fancy, I use an open source program called InstallCert.java to add certificates returned by the Server into my JRE’s truststore. I just ran this program against our LDAP server and port. When it first tried to connect LDAP server using SSL it threw same «PKIX path building failed» error and then prints certificates returned by LDAP server. It will then ask you to add Certificate into keystore just give certificate number as appeared on your screen and it will then add those certificate into «jssecacerts» inside C:Program FilesJavajdk1.6.0jrelibsecurity folder. Now re-run the program that error should be disappeared and it will print:

«Loading KeyStore jssecacerts.
Opening connection to stockmarket.com:636.
Starting SSL handshake.
No errors, certificate is already trusted

You are done, now if you try authenticating against same LDAP server you will succeed. You can also configure the path of the JRE used by your application e.g. if you are running your application inside Tomcat, then you must give the path to the JRE used by Tomcat. You also need to configure HTTPS in Tomcat, which you do by following steps given here.

Here is also a nice diagram which tells what exactly happens when a Java client connect to Java server using https or SSL i.e during SSL handshake:

By the way, this is not the only way to add certificates into the truststore. You can also use the keytool to add certificates into trust store as well. The keytool comes with JDK installation and you can find it inside the bind directory of JAVA_HOME.

This solution is particularly useful when you don’t have the certificates used by Server. If you can contact your infra guys or Linux admin to get certificates then you can use keytool to add those into truststore as shown below:

Источник

Сбои SSL-рукопожатия

Специализированный учебник по сбоям SSL-квитирования и тому, как их исправить.

Автор: Kumar Chandrakant
Дата записи

1. Обзор

Защищенный уровень сокета (SSL) – это криптографический протокол, который обеспечивает безопасность при передаче данных по сети. В этом уроке мы обсудим различные сценарии, которые могут привести к сбою SSL-квитирования, и как это сделать.

Обратите внимание, что наше введение в SSL с использованием JSSE более подробно описывает основы SSL.

2. Терминология

Важно отметить, что из-за уязвимостей безопасности SSL как стандарт заменяется TLS (Transport Layer Security). Большинство языков программирования, включая Java, имеют библиотеки для поддержки как SSL, так и TLS.

С момента создания SSL многие продукты и языки, такие как OpenSSL и Java, имели ссылки на SSL, которые они сохраняли даже после того, как TLS взял верх. По этой причине в оставшейся части этого руководства мы будем использовать термин SSL для обозначения криптографических протоколов.

3. Настройка

Для целей этого урока мы создадим простые серверные и клиентские приложения, использующие API сокетов Java для имитации сетевого подключения.

3.1. Создание Клиента и Сервера

В Java мы можем использовать s pockets для установления канала связи между сервером и клиентом по сети . Сокеты являются частью расширения Java Secure Socket Extension (JSSE) в Java.

Давайте начнем с определения простого сервера:

Сервер, определенный выше, возвращает сообщение “Hello World!” подключенному клиенту.

Далее давайте определим базовый клиент, который будет подключаться к нашему Простому серверу:

Наш клиент печатает сообщение, возвращенное сервером.

3.2. Создание сертификатов на Java

SSL обеспечивает секретность, целостность и подлинность сетевых коммуникаций. Сертификаты играют важную роль в установлении подлинности.

Как правило, эти сертификаты приобретаются и подписываются Центром сертификации, но в этом руководстве мы будем использовать самозаверяющие сертификаты.

Для достижения этой цели мы можем использовать инструмент для ключей, который поставляется с JDK:

Приведенная выше команда запускает интерактивную оболочку для сбора информации для сертификата, такой как Общее имя (CN) и отличительное имя (DN). Когда мы предоставляем все необходимые сведения, он генерирует файл хранилище ключей сервера.jks , который содержит закрытый ключ сервера и его открытый сертификат.

Обратите внимание, что serverkeystore.jks хранится в формате хранилища ключей Java (JKS), который является собственностью Java. В эти дни keytool напомнит нам, что мы должны рассмотреть возможность использования PKCS#12, который он также поддерживает.

Далее мы можем использовать keytool для извлечения открытого сертификата из сгенерированного файла хранилища ключей:

Приведенная выше команда экспортирует открытый сертификат из хранилища ключей в файл server.cer . Давайте используем экспортированный сертификат для клиента, добавив его в хранилище доверия:

Теперь мы создали хранилище ключей для сервера и соответствующее хранилище доверия для клиента. Мы рассмотрим использование этих сгенерированных файлов, когда будем обсуждать возможные сбои при рукопожатии.

Более подробную информацию об использовании хранилища ключей Java можно найти в нашем предыдущем руководстве .

4. SSL-рукопожатие

SSL-квитанции-это механизм, с помощью которого клиент и сервер устанавливают доверие и логистику, необходимые для обеспечения их соединения по сети .

Это очень организованная процедура, и понимание ее деталей может помочь понять, почему она часто терпит неудачу, о чем мы намерены рассказать в следующем разделе.

Типичными шагами в SSL-рукопожатии являются:

  1. Клиент предоставляет список возможных версий SSL и наборов шифров для использования
  2. Сервер соглашается с конкретной версией SSL и набором шифров, отвечая своим сертификатом
  3. Клиент извлекает открытый ключ из сертификата и отвечает зашифрованным “предварительным главным ключом”
  4. Сервер расшифровывает “предварительный главный ключ”, используя свой закрытый ключ
  5. Клиент и сервер вычисляют “общий секрет”, используя обмененный “предварительный главный ключ”
  6. Клиент и сервер обмениваются сообщениями, подтверждающими успешное шифрование и дешифрование с использованием “общего секрета”

Хотя большинство шагов одинаковы для любого SSL-рукопожатия, существует тонкая разница между односторонним и двусторонним SSL. Давайте быстро рассмотрим эти различия.

4.1. Рукопожатие в одностороннем SSL

Если мы обратимся к шагам, упомянутым выше, на втором шаге упоминается обмен сертификатами. Односторонний SSL требует, чтобы клиент мог доверять серверу через свой открытый сертификат. Это оставляет сервер доверять всем клиентам , которые запрашивают соединение. Сервер не может запрашивать и проверять открытый сертификат у клиентов, что может представлять угрозу безопасности.

4.2. Рукопожатие в двустороннем SSL

При использовании одностороннего SSL сервер должен доверять всем клиентам. Но двусторонний SSL добавляет возможность серверу также устанавливать доверенных клиентов. Во время двустороннего рукопожатия и клиент, и сервер должны представить и принять открытые сертификаты друг друга , прежде чем можно будет установить успешное соединение.

5. Сценарии Сбоя Рукопожатия

Проведя этот краткий обзор, мы можем с большей ясностью взглянуть на сценарии сбоев.

SSL-рукопожатие при односторонней или двусторонней связи может завершиться неудачей по нескольким причинам. Мы рассмотрим каждую из этих причин, смоделируем сбой и поймем, как мы можем избежать таких сценариев.

В каждом из этих сценариев мы будем использовать Простой клиент и Простой сервер , которые мы создали ранее.

5.1. Отсутствует сертификат Сервера

Давайте попробуем запустить SimpleServer и подключить его через Simple Client . В то время как мы ожидаем увидеть сообщение “Привет, мир!”, мы представляем исключение:

Теперь это указывает на то, что что-то пошло не так. Исключение SSLHandshakeException выше, абстрактно, указывает, что клиент при подключении к серверу не получил никакого сертификата.

Для решения этой проблемы мы будем использовать хранилище ключей, созданное ранее, передавая их на сервер в качестве системных свойств:

Важно отметить, что системное свойство для пути к файлу хранилища ключей должно быть либо абсолютным путем, либо файл хранилища ключей должен быть помещен в тот же каталог, из которого вызывается команда Java для запуска сервера. Системное свойство Java для хранилища ключей не поддерживает относительные пути.

Помогает ли это нам получить результат, который мы ожидаем? Давайте выясним это в следующем подразделе.

5.2. Сертификат ненадежного Сервера

Когда мы снова запускаем SimpleServer и Simple Client с изменениями в предыдущем подразделе, что мы получаем в качестве вывода:

Ну, это сработало не совсем так, как мы ожидали, но, похоже, это не сработало по другой причине.

Этот конкретный сбой вызван тем, что наш сервер использует самозаверяющий сертификат, который не подписан Центром сертификации (ЦС).

Действительно, каждый раз, когда сертификат подписывается чем-то другим, чем то, что находится в хранилище доверия по умолчанию, мы увидим эту ошибку. Хранилище доверия по умолчанию в JDK обычно поставляется с информацией об обычных используемых автомобилях.

Чтобы решить эту проблему здесь, нам придется заставить Simple Client доверять сертификату, представленному SimpleServer . Давайте воспользуемся хранилищем доверия, которое мы создали ранее, передав их клиенту в качестве системных свойств:

Обратите внимание, что это не идеальное решение. В идеальном сценарии мы должны использовать не самозаверяющий сертификат, а сертификат, сертифицированный Центром сертификации (ЦС), которому клиенты могут доверять по умолчанию.

Давайте перейдем к следующему подразделу, чтобы узнать, получим ли мы ожидаемый результат сейчас.

5.3. Отсутствие Сертификата Клиента

Давайте попробуем еще раз запустить Простой сервер и Простой клиент, применив изменения из предыдущих подразделов:

Опять же, не то, что мы ожидали. Исключение SocketException здесь говорит нам, что сервер не может доверять клиенту. Это связано с тем, что мы установили двусторонний SSL. В нашем Простом сервере у нас есть:

Приведенный выше код указывает на SSLServerSocket требуется для аутентификации клиента через его публичный сертификат.

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

Мы перезагрузим сервер и передадим ему следующие системные свойства:

Затем мы перезапустим клиент, передав эти системные свойства:

Наконец, у нас есть желаемый результат:

5.4. Неверные Сертификаты

Помимо вышеперечисленных ошибок, рукопожатие может завершиться неудачей по целому ряду причин, связанных с тем, как мы создали сертификаты. Одна распространенная ошибка связана с неправильным CN. Давайте рассмотрим детали хранилища ключей сервера, которое мы создали ранее:

Когда мы выполняем приведенную выше команду, мы можем увидеть детали хранилища ключей, в частности владельца:

CN владельца этого сертификата имеет значение localhost. CN владельца должен точно соответствовать хосту сервера. Если есть какое-либо несоответствие, это приведет к исключению SSLHandshakeException .

Давайте попробуем восстановить сертификат сервера с помощью CN как что-либо другое, кроме localhost. Когда мы теперь используем восстановленный сертификат для запуска SimpleServer и SimpleClient , он быстро выходит из строя:

Трассировка исключений выше ясно указывает на то, что клиент ожидал сертификат с именем localhost, который он не нашел.

Обратите внимание, что JSSE по умолчанию не требует проверки имени хоста. Мы включили проверку имени хоста в Простом клиенте с помощью явного использования HTTPS:

Проверка имени хоста является распространенной причиной сбоя и в целом и всегда должна выполняться для повышения безопасности. Для получения подробной информации о проверке имени хоста и ее важности для безопасности с помощью TLS, пожалуйста, обратитесь к этой статье .

5.5. Несовместимая версия SSL

В настоящее время существуют различные криптографические протоколы, включая различные версии SSL и TLS.

Как упоминалось ранее, SSL, в целом, был заменен TLS из-за его криптографической прочности. Криптографический протокол и версия являются дополнительным элементом, который клиент и сервер должны согласовать во время рукопожатия.

Например, если сервер использует криптографический протокол SSL 3, а клиент использует TLS1.3, они не могут договориться о криптографическом протоколе, и будет сгенерировано исключение SSLHandshakeException .

В нашем Простом клиенте давайте изменим протокол на что-то, что не совместимо с протоколом, установленным для сервера:

Когда мы снова запустим наш клиент, мы получим исключение SSLHandshakeException :

Трассировка исключений в таких случаях является абстрактной и не говорит нам о точной проблеме. Для решения этих типов проблем необходимо убедиться, что и клиент, и сервер используют одни и те же или совместимые криптографические протоколы.

5.6. Несовместимый набор шифров

Клиент и сервер также должны договориться о наборе шифров, которые они будут использовать для шифрования сообщений.

Во время рукопожатия клиент представит список возможных шифров для использования, и сервер ответит выбранным шифром из списка. Сервер сгенерирует исключение SSLHandshakeException , если не сможет выбрать подходящий шифр.

В нашем Простом клиенте давайте изменим набор шифров на что-то, что не совместимо с набором шифров, используемым нашим сервером:

Когда мы перезапустим наш клиент, мы получим исключение SSLHandshakeException :

Опять же, трассировка исключений довольно абстрактна и не говорит нам о точной проблеме. Решение такой ошибки заключается в проверке включенных наборов шифров, используемых как клиентом, так и сервером, и обеспечении наличия по крайней мере одного общего набора.

Обычно клиенты и серверы настроены на использование широкого спектра наборов шифров, поэтому вероятность возникновения этой ошибки меньше. Если мы сталкиваемся с этой ошибкой, это обычно связано с тем, что сервер настроен на использование очень избирательного шифра. Сервер может выбрать принудительное применение выборочного набора шифров по соображениям безопасности.

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

В этом уроке мы узнали о настройке SSL с помощью сокетов Java. Затем мы обсудили SSL-рукопожатия с односторонним и двусторонним SSL. Наконец, мы рассмотрели список возможных причин, по которым SSL-рукопожатия могут не сработать, и обсудили решения.

Как всегда, код для примеров доступен на GitHub .

Источник

  1. SSL Handshakes in Java
  2. Fix the SSLHandshakeException Because of Missing Server Certificate
  3. Fix the SSLHandShakeException Because of Untrusted Server Certificate
  4. Fix the SSLHandShakeException Because of Incorrect Certificate
  5. Fix the SSLHandShakeException Because of Incompatible SSL Version and Cipher Suite

Fix the Javax.Net.SSL.SSLHandshakeException Error

This tutorial demonstrates the javax.net.ssl.SSLHandshakeException error in Java.

SSL Handshakes in Java

The SSL Handshakes are used for the client and server to establish trust and logistics required to secure the connection over the internet. There are typical steps in SSL Handshake operations which are needed to be followed:

  1. First, the client will provide the list of all possible cipher suites and SSL versions.
  2. The server will then agree on the particular cipher suite and SSL version, which will respond with a certificate.
  3. Then, the client will extract the public key from the given certificate and respond with the new encrypted pre-master key.
  4. Then, the server will use the private key to decrypt the pre-master key.
  5. Then, the client and server will compute the shared secret using the pre-master key together.
  6. Finally, the client and server will exchange messages which confirm the successful encryption and decryption of the shared secret.

The SSL Handshakes have two types. The first is the one-way SSL, which leaves the server to trust all the clients, and the second is the two-way SSL in which the client and server must accept each other’s certificates.

After understanding the SSL Handshakes, we can now discuss the SSLHandShakeException in detail. There are two scenarios of SSLHandShakeException, which are given below.

Fix the SSLHandshakeException Because of Missing Server Certificate

If an SSL Handshake operation when the client is connecting to the server did not receive any certificate, it would throw the SSLHandShakeException as mentioned below:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  Received fatal alert: handshake_failure

To solve this issue, make sure you follow all the steps above. This problem occurs when the Keystore or the system properties are not entered properly.

Keystores are the certificates provided by the authorities, or we can also create our Keystores by using the keytool functionality of JDK. Here is an example for the Keystore:

$ keytool -genkey -keypass password 
                  -storepass password 
                  -keystore Server_Keystore.jks

The above keytool code is written in the Keystore file. Now the keytool can be used to extract a public certificate from the Keystore file which was generated above:

$ keytool -export -storepass password 
                  -file NewServer.cer 
                  -keystore Server_Keystore.jks

The above code will export the public certificate from the Keystore as a file NewServer.cer. Now, we can add it to the Truststore for the client:

$ keytool -import -v -trustcacerts 
                     -file NewServer.cer 
                     -keypass password 
                     -storepass password 
                     -keystore Client_Truststore.jks

Now the Keystore for the server and Truststore for the client are generated. We can pass them as system properties to the server with a command:

-Djavax.net.ssl.keyStore=Client_Keystore.jks -Djavax.net.ssl.keyStorePassword=password

It is necessary for the system property. The Keystore file path must be absolute or place the Keystore file in the same directory from where the command is invoked.

The relative paths are not supported. Once you follow this process, the missing certificate error will be solved, and there will be no more SSLHandShakeException.

Fix the SSLHandShakeException Because of Untrusted Server Certificate

The other reason for SSLHandShakeException is an untrusted server certificate. When a server is using a self-signed certificate that is not signed by authorities, it will throw the following error:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  sun.security.validator.ValidatorException:
  PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
  unable to find valid certification path to requested target

This exception will be thrown whenever the certificate is signed by any entity other than the default store. The default Truststore in JDK ships the information about common certificates in use.

This issue can be solved by forcing the client to trust the certificate presented by the server. We need to use the Truststore we generated above and pass them as system properties to the client:

-Djavax.net.ssl.trustStore=Client_Truststore.jks -Djavax.net.ssl.trustStorePassword=password

This will solve the exception, but it is not an ideal situation. In an ideal situation, we can use the self-signed certificate, which should be certified by the Certificate Authority (CA), then the client can trust them by default.

Fix the SSLHandShakeException Because of Incorrect Certificate

A handshake can also fail because of an incorrect certificate. When a certificate is not created properly, it will throw the SSLHandShakeException:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
    java.security.cert.CertificateException:
    No name matching localhost found

To check if the certificate is created properly, run the following command:

keytool -v -list -keystore Server_Keystore.jks

The above command will show the details of the Keystore owner:

...
Owner: CN=localhost, OU=technology, O=delftstack, L=city, ST=state, C=xx
..

The owner’s CN must match the server’s CN, and if it doesn’t match, it will throw the same exception shown above as it is generated because of the different CN.

Fix the SSLHandShakeException Because of Incompatible SSL Version and Cipher Suite

While an SSL handshake operation, it is possible that there will be various cryptographic protocols like different versions of SSL, TLS, etc. While the client and server must agree on cryptographic protocols and versions on a handshake, the SSL is superseded by the TLS for its cryptographic strength.

Now, for example, if the server is using the protocol SSL3, and the client is using the protocol TLS1.3, both cannot agree on the cryptographic protocol, and it will throw the SSLHandShakeException:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

To solve this issue, we must verify that client and server are using either the same or compatible cryptographic protocols.

Similarly, it is also necessary to have the compatible Cipher Suite. While a handshake, the client provides the list of ciphers, and the server will select a cipher to use.

If the server cannot select a suitable cipher, the code will throw the following SSLHandShakeException:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  Received fatal alert: handshake_failure

Normally the client and server use a variety of cipher suites; that is why this error can occur. The error occurs because a server has chosen a very selective cipher.

To avoid this issue, the server uses a list of selective ciphers, which is also good for security.

SSLHandshakeException appear in logs when there is some error occur while validating the certificate installed in client machine with certificate on server machine. In this post, we will learn about fixing this if you are using Apache HttpClient library to create HttpClient to connect to SSL/TLS secured URLs.

The exception logs will look like this.

Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:980)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
	at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:117)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
	at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:88)
	at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46)
	at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:49)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:509)
	... 61 more
Caused by: java.io.EOFException: SSL peer shut down incorrectly
	at sun.security.ssl.InputRecord.read(InputRecord.java:505)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:961)
	... 80 more

I have already posted code fix to bypass SSL matching in earlier post.

Unfortunately, that fix works in TLS and TLS 1.1 protocols. It doesn’t work in TLS 1.2 protocol. So ultimately, you need to fix the certificate issue anyway. There is ‘no code only’ fix for this.

Now there are two ways, you can utilize the imported certificate from server. Either add certificate to the JDK cacerts store; or pass certificate information in JVM aruguments.

1) Import certificate to JDK cacert store

  1. Import the certificate from server.
  2. Use given command to add the certificate to JDK store. (Remove new line characters).
    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
    

Now create HTTP client as given:

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;
}

Notice the code : SSLContext.getInstance("TLSv1.2"). This code picks up the certificates added to JDK cacert store. So make a note of it.

2) Pass certificate information in JVM aruguments

  1. Import the certicate from server.
  2. Add JVM arguments while starting the server. Change the parameter values as per your application.
    -Djavax.net.ssl.keyStore="C:/Users/Lokeshkeysmaven.jks" 
    -Djavax.net.ssl.keyStorePassword="test" 
    -Djavax.net.ssl.trustStore="C:/Users/Lokeshkeysmaven.jks" 
    -Djavax.net.ssl.trustStorePassword="test" 
    

Now create HTTP client as given:

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;
}

Notice the code : SSLContext.createSystemDefault(). This code picks up the certificates passed as JVM arguments. Again, make a note of it.

Summary

  1. Use SSLContext.getInstance("TLSv1.2") when certificate is added to JDK cacert store.
  2. Use SSLContext.createSystemDefault() when SSL info is passed as JVM argument.

Drop me your questions in comments section.

Happy Learning !!

Сбой SSL рукопожатия

1. обзор

Secured Socket Layer (SSL) — это криптографический протокол, который обеспечивает безопасность связи по сети. In this tutorial, we’ll discuss various scenarios that can result in an SSL handshake failure and how to it.с

2. терминология

Важно отметить, что из-за уязвимостей системы безопасности SSL как стандарт заменяется безопасностью транспортного уровня (TLS). Большинство языков программирования, включая Java, имеют библиотеки для поддержки как SSL, так и TLS.

С момента появления SSL многие продукты и языки, такие как OpenSSL и Java, имели ссылки на SSL, которые они сохраняли даже после вступления в силу TLS. По этой причине в оставшейся части этого руководства мы будем использовать термин SSL для общего обозначения криптографических протоколов.

3. Настроить

Для целей этого руководства мы создадим простые серверные и клиентские приложения, используяthe Java Socket API для имитации сетевого подключения.

3.1. Создание клиента и сервера

В Java мы можем использоватьsockets to establish a communication channel between a server and client over the network. Сокеты являются частью Java Secure Socket Extension (JSSE) в Java.

Начнем с определения простого сервера:

int port = 8443;
ServerSocketFactory factory = SSLServerSocketFactory.getDefault();
try (ServerSocket listener = factory.createServerSocket(port)) {
    SSLServerSocket sslListener = (SSLServerSocket) listener;
    sslListener.setNeedClientAuth(true);
    sslListener.setEnabledCipherSuites(
      new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" });
    sslListener.setEnabledProtocols(
      new String[] { "TLSv1.2" });
    while (true) {
        try (Socket socket = sslListener.accept()) {
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            out.println("Hello World!");
        }
    }
}

Определенный выше сервер возвращает сообщение «Hello World!» Подключенному клиенту.

Затем давайте определим базового клиента, которого мы подключим к нашемуSimpleServer:

String host = "localhost";
int port = 8443;
SocketFactory factory = SSLSocketFactory.getDefault();
try (Socket connection = factory.createSocket(host, port)) {
    ((SSLSocket) connection).setEnabledCipherSuites(
      new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" });
    ((SSLSocket) connection).setEnabledProtocols(
      new String[] { "TLSv1.2" });

    SSLParameters sslParams = new SSLParameters();
    sslParams.setEndpointIdentificationAlgorithm("HTTPS");
    ((SSLSocket) connection).setSSLParameters(sslParams);

    BufferedReader input = new BufferedReader(
      new InputStreamReader(connection.getInputStream()));
    return input.readLine();
}

Наш клиент печатает сообщение, возвращаемое сервером.

3.2. Создание сертификатов в Java

SSL обеспечивает секретность, целостность и аутентичность в сетевых коммуникациях. Сертификаты играют важную роль в установлении подлинности.

Обычно эти сертификаты приобретаются и подписываются центром сертификации, но в этом руководстве мы будем использовать самозаверяющие сертификаты.

Для этого мы можем использоватьkeytool, w, который поставляется с JDK:

$ keytool -genkey -keypass password 
                  -storepass password 
                  -keystore serverkeystore.jks

Приведенная выше команда запускает интерактивную оболочку для сбора информации для сертификата, например Common Name (CN) и Distinguished Name (DN). Когда мы предоставляем всю необходимую информацию, он генерирует файлserverkeystore.jks, который содержит закрытый ключ сервера и его открытый сертификат.

Обратите внимание, чтоserverkeystore.jks  хранится в формате Java Key Store (JKS), который является проприетарным для Java. These days, keytool will remind us that we ought to consider using PKCS#12, which it also supports.

Далее мы можем использоватьkeytool to для извлечения публичного сертификата из сгенерированного файла хранилища ключей:

$ keytool -export -storepass password 
                  -file server.cer 
                  -keystore serverkeystore.jks

Приведенная выше команда экспортирует открытый сертификат из хранилища ключей как файлserver.cer. Давайте использовать экспортированный сертификат для клиента, добавив его в его хранилище доверенных сертификатов:

$ keytool -import -v -trustcacerts 
                     -file server.cer 
                     -keypass password 
                     -storepass password 
                     -keystore clienttruststore.jks

Теперь мы создали хранилище ключей для сервера и соответствующее хранилище доверенных сертификатов для клиента. Мы рассмотрим использование этих сгенерированных файлов, когда будем обсуждать возможные сбои рукопожатия.

И более подробную информацию об использовании хранилища ключей Java можно найти в нашемprevious tutorial.

4. Подтверждение SSL

Подтверждения SSL составляютa mechanism by which a client and server establish the trust and logistics required to secure their connection over the network.

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

Типичные шаги в рукопожатии SSL:

  1. Клиент предоставляет список возможных версий SSL и наборов шифров для использования

  2. Сервер соглашается на конкретную версию SSL и набор шифров, отвечая своим сертификатом

  3. Клиент извлекает открытый ключ из сертификата и отвечает зашифрованным «предварительным главным ключом»

  4. Сервер расшифровывает «предварительный мастер-ключ», используя свой закрытый ключ

  5. Клиент и сервер вычисляют «общий секрет», используя обмененный «предварительный мастер-ключ»

  6. Клиент и сервер обмениваются сообщениями, подтверждающими успешное шифрование и дешифрование с использованием «общего секрета»

Хотя большинство шагов одинаковы для любого рукопожатия SSL, между односторонним и двусторонним SSL есть небольшая разница. Давайте быстро рассмотрим эти различия.

4.1. Рукопожатие в одностороннем SSL

Если мы ссылаемся на шаги, упомянутые выше, на шаге два упоминается обмен сертификатами. Односторонний SSL требует, чтобы клиент мог доверять серверу через свой открытый сертификат. Этоleaves the server to trust all clients, которые запрашивают соединение. Сервер не может запрашивать и проверять общедоступный сертификат у клиентов, что может представлять угрозу безопасности.

4.2. Рукопожатие в двустороннем SSL

При использовании одностороннего SSL сервер должен доверять всем клиентам. Но двусторонний SSL добавляет возможность для сервера также устанавливать доверенных клиентов. Во время двустороннего рукопожатияboth the client and server must present and accept each other’s public certificates перед установкой успешного соединения.

5. Сценарии отказа рукопожатия

Сделав этот быстрый обзор, мы можем более четко рассмотреть сценарии сбоев.

Рукопожатие SSL при односторонней или двусторонней связи может завершиться неудачей по нескольким причинам. Мы рассмотрим каждую из этих причин, смоделируем сбой и поймем, как мы можем избежать таких сценариев.

В каждом из этих сценариев мы будем использоватьSimpleClient иSimpleServer, которые мы создали ранее.

5.1. Отсутствует сертификат сервера

Давайте попробуем запуститьSimpleServer и подключить его черезSimpleClient. Хотя мы ожидаем увидеть сообщение «Hello World!», Мы представляем исключение:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  Received fatal alert: handshake_failure

Теперь это означает, что что-то пошло не так. SSLHandshakeException выше, абстрактно,is stating that the client when connecting to the server did not receive any certificate.

Для решения этой проблемы мы будем использовать хранилище ключей, которое мы сгенерировали ранее, передавая их в качестве системных свойств серверу:

-Djavax.net.ssl.keyStore=clientkeystore.jks -Djavax.net.ssl.keyStorePassword=password

Важно отметить, что системное свойство для пути к файлу хранилища ключей должно быть либо абсолютным путем, либо файл хранилища ключей должен быть помещен в тот же каталог, из которого вызывается команда Java для запуска сервера. Java system property for keystore does not support relative paths.с

Помогает ли это нам получить ожидаемый результат? Давайте узнаем в следующем подразделе.

5.2. Сертификат ненадежного сервера

Когда мы снова запустимSimpleServer иSimpleClient с изменениями в предыдущем подразделе, что мы получим в качестве вывода:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  sun.security.validator.ValidatorException:
  PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
  unable to find valid certification path to requested target

Ну, это не сработало так, как мы ожидали, но похоже, что это не удалось по другой причине.

Эта конкретная ошибка вызвана тем, что наш сервер использует сертификатself-signed, который не подписан центром сертификации (CA).

Really, any time the certificate is signed by something other than what is in the default truststore, we’ll see this error. Склад доверенных сертификатов по умолчанию в JDK обычно поставляется с информацией об используемых общих центрах сертификации.

Чтобы решить эту проблему здесь, нам придется заставитьSimpleClient доверять сертификату, представленномуSimpleServer. Давайте воспользуемся хранилищем доверенных сертификатов, которое мы создали ранее, передав их клиенту как системные свойства:

-Djavax.net.ssl.trustStore=clienttruststore.jks -Djavax.net.ssl.trustStorePassword=password

Обратите внимание, что это не идеальное решение. In an ideal scenario, we should not use a self-signed certificate but a certificate which has been certified by a Certificate Authority (CA) which clients can trust by default.с

Давайте перейдем к следующему подразделу, чтобы узнать, получим ли мы ожидаемый результат сейчас.

5.3. Отсутствует сертификат клиента

Давайте попробуем еще раз запустить SimpleServer и SimpleClient, применив изменения из предыдущих подразделов:

Exception in thread "main" java.net.SocketException:
  Software caused connection abort: recv failed

Опять же, не то, что мы ожидали. SocketException здесь говорит нам, что сервер не может доверять клиенту. Это потому, что мы настроили двусторонний SSL. В нашемSimpleServer we:

((SSLServerSocket) listener).setNeedClientAuth(true);

Приведенный выше код указывает, чтоSSLServerSocket требуется для аутентификации клиента через его открытый сертификат.

Мы можем создать хранилище ключей для клиента и соответствующее хранилище доверенных сертификатов для сервера способом, аналогичным тому, который мы использовали при создании предыдущего хранилища ключей и хранилища доверенных сертификатов.

Мы перезапустим сервер и передадим ему следующие системные свойства:

-Djavax.net.ssl.keyStore=serverkeystore.jks 
    -Djavax.net.ssl.keyStorePassword=password 
    -Djavax.net.ssl.trustStore=servertruststore.jks 
    -Djavax.net.ssl.trustStorePassword=password

Затем мы перезапустим клиент, передав следующие системные свойства:

-Djavax.net.ssl.keyStore=clientkeystore.jks 
    -Djavax.net.ssl.keyStorePassword=password 
    -Djavax.net.ssl.trustStore=clienttruststore.jks 
    -Djavax.net.ssl.trustStorePassword=password

Наконец, у нас есть желаемый результат:

5.4. Неверные сертификаты

Помимо вышеперечисленных ошибок, рукопожатие может потерпеть неудачу из-за множества причин, связанных с тем, как мы создали сертификаты. Одна распространенная ошибка связана с неправильным CN. Давайте подробно рассмотрим созданное нами ранее хранилище ключей сервера:

keytool -v -list -keystore serverkeystore.jks

Когда мы запускаем указанную выше команду, мы можем видеть детали хранилища ключей, в частности, владельца:

...
Owner: CN=localhost, OU=technology, O=example, L=city, ST=state, C=xx
...

CN владельца этого сертификата установлен на localhost. CN владельца должен точно соответствовать хосту сервера. Если есть какое-либо несоответствие, это приведет кSSLHandshakeException.

Давайте попробуем повторно сгенерировать сертификат сервера с CN как что-нибудь кроме localhost. Когда мы используем регенерированный сертификат сейчас для запускаSimpleServer иSimpleClient, он сразу же терпит неудачу:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
    java.security.cert.CertificateException:
    No name matching localhost found

Приведенная выше трассировка исключений ясно указывает на то, что клиент ожидал сертификат с именем localhost, который он не нашел.

Обратите внимание, чтоJSSE does not mandate hostname verification by default. Мы включили проверку имени хоста вSimpleClient посредством явного использования HTTPS:

SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
((SSLSocket) connection).setSSLParameters(sslParams);

Проверка имени хоста является распространенной причиной сбоев и, как правило, всегда должна применяться для обеспечения большей безопасности. Дополнительные сведения о проверке имени хоста и ее важности для безопасности с помощью TLS см. Вthis article.

5.5. Несовместимая версия SSL

В настоящее время используются различные криптографические протоколы, в том числе разные версии SSL и TLS.

Как упоминалось ранее, SSL, в общем, был заменен TLS из-за своей криптографической стойкости. Криптографический протокол и версия являются дополнительным элементом, с которым клиент и сервер должны договориться во время рукопожатия.

Например, если сервер использует криптографический протокол SSL3, а клиент использует TLS1.3, они не могут договориться о криптографическом протоколе, и будет сгенерированSSLHandshakeException.

В нашемSimpleClient давайте изменим протокол на то, что несовместимо с протоколом, установленным для сервера:

((SSLSocket) connection).setEnabledProtocols(new String[] { "TLSv1.1" });

Когда мы снова запустим наш клиент, мы получимSSLHandshakeException:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

Трассировка исключений в таких случаях является абстрактной и не говорит нам точную проблему. To resolve these types of problems it is necessary to verify that both the client and server are using either the same or compatible cryptographic protocols.с

5.6. Несовместимый Cipher Suite

Клиент и сервер также должны договориться о наборе шифров, который они будут использовать для шифрования сообщений.

Во время рукопожатия клиент представит список возможных шифров для использования, и сервер ответит выбранным шифром из списка. Сервер сгенерируетSSLHandshakeException , если не сможет выбрать подходящий шифр.

В нашемSimpleClient давайте изменим набор шифров на что-то, несовместимое с набором шифров, используемым нашим сервером:

((SSLSocket) connection).setEnabledCipherSuites(
  new String[] { "TLS_RSA_WITH_AES_128_GCM_SHA256" });

Когда мы перезапустим наш клиент, мы получимSSLHandshakeException:

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  Received fatal alert: handshake_failure

Опять же, трассировка исключений довольно абстрактна и не говорит нам точную проблему. Решение этой ошибки заключается в проверке включенных комплектов шифров, используемых клиентом и сервером, и в наличии хотя бы одного общего комплекта.

Как правило, клиенты и серверы настроены на использование широкого набора наборов шифров, поэтому вероятность возникновения этой ошибки меньше. If we encounter this error it is typically because the server has been configured to use a very selective cipher. Сервер может выбрать принудительное применение выборочного набора шифров по соображениям безопасности.

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

В этом уроке мы узнали о настройке SSL с использованием сокетов Java. Затем мы обсудили рукопожатия SSL с односторонним и двусторонним SSL. Наконец, мы рассмотрели список возможных причин, по которым рукопожатия SSL могут потерпеть неудачу, и обсудили решения.

Disclosure: This article may contain affiliate links. When you purchase, we may earn a small commission.

If you are working in a Java web or enterprise application that connects to any other web server using HTTPS you might have seen the «javax.net.ssl.SSLHandshakeException». This is one of the particular cases of that error. If you know how SSL and HTTPS work that when a Java client connects to a Java server the SSL handshake happens. In these steps server return certificates to confirm its identity, which the client validates against the root certificate he has in its truststore. If Server returns a certificate that cannot be validated against the certificates a browser or Java client holds in its truststore then it throws the «sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target».

In other words, while connecting to any website or server using SSL or HTTPS in Java, sometimes you may face a problem of «unable to find valid certification path to requested target» exception  as shown below:


javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

The reason of this error is simple, certificates returned by the Server during SSL handshake are not signed by any trusted Certification Authority(CA) which are configured in your JRE’s truststore e.g Verisign, Thwate, GoDaddy, or Entrust etc.

Instead, the Server is sending a certificate that is unknown to JRE and that’s why it’s not able to validate those certifications against the private key he holds in his truststore.

If you remember, there is a subtle difference between keystore and truststore in Java. Even though, both stores certificates, keystore is used to store your credential (server or client) while truststore is used to store other credentials (Certificates from CA).

This could also happen when Server is sending certificate from other certificate authority which is not configured in JRE’s truststore i.e. some internal certificate signed by your company.

I got the exactly same error while connecting to our LDAP server using SSL from my Spring Security based Java web application. Since LDAP server was internal to the company, it was sending internally signed certificates which were not present in the Tomcat’s JRE (Java Runtime Environment).

To solve this problem you need to add certificates returned by the Server into your JRE’s truststore, which you can do by using keytool or other tools provided by your company.

How did I solved this Problem?

Nothing fancy, I use an open source program called InstallCert.java to add certificates returned by the Server into my JRE’s truststore. I just ran this program against our LDAP server and port. When it first tried to connect LDAP server using SSL it threw same «PKIX path building failed» error and then prints certificates returned by LDAP server. It will then ask you to add Certificate into keystore just give certificate number as appeared on your screen and it will then add those certificate into «jssecacerts» inside C:Program FilesJavajdk1.6.0jrelibsecurity folder. Now re-run the program that error should be disappeared and it will print:

«Loading KeyStore jssecacerts…
Opening connection to stockmarket.com:636…
Starting SSL handshake…
No errors, certificate is already trusted

You are done, now if you try authenticating against same LDAP server you will succeed. You can also configure the path of the JRE used by your application e.g. if you are running your application inside Tomcat, then you must give the path to the JRE used by Tomcat. You also need to configure HTTPS in Tomcat, which you do by following steps given here.

Here is also a nice diagram which tells what exactly happens when a Java client connect to Java server using https or SSL i.e during SSL handshake:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

By the way, this is not the only way to add certificates into the truststore. You can also use the keytool to add certificates into trust store as well. The keytool comes with JDK installation and you can find it inside the bind directory of JAVA_HOME.

This solution is particularly useful when you don’t have the certificates used by Server. If you can contact your infra guys or Linux admin to get certificates then you can use keytool to add those into truststore as shown below:

$ keytool -import -alias -ca -file /tmp/root_cert.cer -keystore cacerts

You can see here for some more examples of using keytool command in Java e.g. listing all certificates it has currently etc.

Понравилась статья? Поделить с друзьями:
  • Connect error 10060 thunderbird
  • Connect error 10060 outlook
  • Congestion apex legends как исправить
  • Confluence как изменить размер шрифта
  • Confluence как изменить порядок страниц