Возникла задача — обеспечить работу java программы в качестве клиента по протоколу ssl.
Программой был Apache Tomcat но изложенный материал можно применить к любой java программе.
Не смотря на то, что до этого имелся опыт по настройке SSL в java, с необходимостью использовать уже сгенерированный приватный ключ и подписанный клиентский сертификат, столкнулся впервые. Пытаясь решить поставленную задачу наступил на пару граблей. Тому как этого избежать и посвящен данный пост.
Есть web приложение размещенное под Tomcat. Сам Tomcat «стоит» за Apache подключенный посредством модуля mod_jk. В процессе подключения приложения к платежной системе возникла необходимость обеспечить доступность данного приложения по протоколу ssl. Нами был сгенерирован приватный клиентский ключ (сert.key), отправлен запрос на получения сертификата и получен сам сертификат (сert.crt) и корневой сертификат (ca.crt). С настройкой ssl на Apache проблем не возникло, в сети полно примеров. Так как Tomcat подключен к Apache по AJP протоколу, никаких дополнительных настроек Tomcat не потребовалось. Всё заработало.
Далее, приложению потребовалось обратиться к web сервису платежной системы. Протокол естественно ssl но в добавок ещё авторизация клиента через выданный клиентский сертификат. В итоге на наш вызов web сервиса получаем
На этом этапе вспоминаем как работать в java с ssl и добавляем в строку запуска Tomcat
(если быть точнее в переменную JAVA_OPTS, но это не суть важно) параметры
В trust.ks (trustStore) необходимо разместить корневой сертификат, в key.ks (keyStore) соответственно клиентский.
Размещаем корневой сертификат:
keytool -keystore server.ks -storepass 123456 -import -file ca.crt
Теперь очередь за клиентским. И вот тут грабли раз — как разместить сert.key и cert.crt в key.ks?
Не буду перечислять мои изыскания, сразу приведу решение:
После чего всё заработало.
Программой был Apache Tomcat но изложенный материал можно применить к любой java программе.
Не смотря на то, что до этого имелся опыт по настройке SSL в java, с необходимостью использовать уже сгенерированный приватный ключ и подписанный клиентский сертификат, столкнулся впервые. Пытаясь решить поставленную задачу наступил на пару граблей. Тому как этого избежать и посвящен данный пост.
Описание задачи
Есть web приложение размещенное под Tomcat. Сам Tomcat «стоит» за Apache подключенный посредством модуля mod_jk. В процессе подключения приложения к платежной системе возникла необходимость обеспечить доступность данного приложения по протоколу ssl. Нами был сгенерирован приватный клиентский ключ (сert.key), отправлен запрос на получения сертификата и получен сам сертификат (сert.crt) и корневой сертификат (ca.crt). С настройкой ssl на Apache проблем не возникло, в сети полно примеров. Так как Tomcat подключен к Apache по AJP протоколу, никаких дополнительных настроек Tomcat не потребовалось. Всё заработало.
Далее, приложению потребовалось обратиться к web сервису платежной системы. Протокол естественно ssl но в добавок ещё авторизация клиента через выданный клиентский сертификат. В итоге на наш вызов web сервиса получаем
HTTP/1.0 403 Client certificate required
На этом этапе вспоминаем как работать в java с ssl и добавляем в строку запуска Tomcat
(если быть точнее в переменную JAVA_OPTS, но это не суть важно) параметры
-Djavax.net.ssl.trustStore=trust.ks
-Djavax.net.ssl.trustStorePassword=123456
-Djavax.net.ssl.keyStore=key.ks
-Djavax.net.ssl.keyStorePassword=123456
В trust.ks (trustStore) необходимо разместить корневой сертификат, в key.ks (keyStore) соответственно клиентский.
Размещаем корневой сертификат:
keytool -keystore server.ks -storepass 123456 -import -file ca.crt
Теперь очередь за клиентским. И вот тут грабли раз — как разместить сert.key и cert.crt в key.ks?
Не буду перечислять мои изыскания, сразу приведу решение:
- Объединяем содержимое файлов cert.key и cert.crt в один и называем его например сert.pem
- Качаем программу Portecle (http://portecle.sourceforge.net) GUI программа для работы с хранилищем сертификатов java
- Открываем программой наш key.ks, потом Tools->Import Key Pair и выбираем cert.pem
- Далее программа попросит указать пароль для импортируемой «Ключевой Пары». И здесь меня поджидали вторые грабли. Пароль для «Ключевой Пары» ДОЛЖЕН СОВПАДАТЬ с паролем хранилища. В нашем случае это 123456.
После чего всё заработало.
Небольшие комментарии
- не указывать пароль для хранилища ключей нельзя. В этом случае возникает ошибка java.security.UnrecoverableKeyException: Password must not be null
- при несоответствии паролей хранилища и «Ключевой Пары» возникает ошибка java.security.UnrecoverableKeyException: Cannot recover key
- пароль «Ключевой Пары» это фактически пароль для дополнительной защиты приватного клиентского ключа (cert.key), его может в файле и не быть. В моём случае приватный клиентский ключ был первоначально сгененрирован openSSH как раз без пароля
- я так и не смог импортировать «Ключевую Пару» в хранилище с помощью программы keytool, если кто знает как это сделать пожалуйста поделитесь
- статья о различных сценариях использования SSL сертификатов сервером и клиентом (на английском) http://community.jboss.org/wiki/sslsetup