Взаимная аутентификация с помощью Tomcat 7

Я пытаюсь настроить веб-службу Java, работающую в Tomcat 7, для использования взаимной (двухсторонней) аутентификации. Кажется, что независимо от того, что я делаю, подключение к службе на защищенном порту не работает.

Вот что я сделал для создания сертификатов и хранилищ ключей и т.д.

//create the key and certificate for the tomcat server.
keytool -genkey -v -alias tomcat -keyalg RSA -validity 3650 -keystore tomcat.keystore

//create the key and certificate for the client machine.
keytool -genkey -v -alias clientkey -keyalg RSA -storetype PKCS12 -keystore client.p12

//export the client key
keytool -export -alias clientkey -keystore client.p12 -storetype PKCS12 -rfc -file client.cer

//import the client key into the server keystore
keytool -import -v -file client.cer -keystore tomcat.keystore

Здесь соединитель в файле server.xml:

<Connector port="8443"
    maxThreads="150"
    scheme="https"
    secure="true"
    sslProtocol="TLS"
    clientAuth="true"
    keystoreFile="tomcat.keystore"
    keystorePass="tomcat"
    truststoreFile="tomcat.keystore"
    truststorePass="tomcat"/>

Файл tomcat-users.xml выглядит следующим образом:

<tomcat-users>
    <role rolename="tomcat"/>
    <role rolename="admin"/>
    <!-- note that the actual values for CN, OU, O, L, ST are different, but they match the values created in the client certificate -->
    <user username="CN=name, OU=unit, O=org, L=locality, ST=state, C=US" password="null" roles="admin" />
</tomcat-users>

При запуске устанавливаются следующие параметры:

-Djavax.net.ssl.keyStoreType=jks
-Djavax.net.ssl.keyStore=tomcat.keystore
-Djavax.net.ssl.keyStorePassword=tomcat
-Djavax.net.ssl.trustStore=tomcat.keystore
-Djavax.net.ssl.trustStorePassword=tomcat
-Djavax.net.debug=SSL

Наконец, я скопировал файл client.p12 на свой клиентский компьютер и импортировал его в сертификаты клиента Firefox.

Первая проблема: Когда я ударил конечную точку на моем сервисе (пример - https://my.server.com:8443/test) из Firefox, я получил ответ "Безопасное соединение сбой". SSL получил запись, которая превысила максимально допустимую длину. (Код ошибки: ssl_error_rx_record_too_long)

Вторая проблема: Я действительно не хочу запускать этот разъем на порту 8443. Я хочу запустить его на порте 7800 (который является нашим стандартом для HTTPS). Когда я меняю порт на соединителе на 7800 и пытаюсь попасть в конечную точку (пример - https://my.server.com:7800/test), он никогда не разрешает страницу.

Итак, где-то я, очевидно, не вижу ключевой части. Может ли кто-нибудь увидеть мою ошибку?

UPDATE: после обратной связи от @Dave G

Запуск команды:

openssl s_client -connect localhost:8443 -showcerts

выводит следующий результат:

CONNECTED(00000003)
140642290976584:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:766:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 263 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

Я также добавил -Djavax.net.debug = SSL для запуска. Это создает в начале файла catalina.out следующее:

trustStore is: tomcat.keystore
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
  Subject: CN=localhost, OU=unit, O=org, L=Springfield, ST=MO, C=US
  Issuer:  CN=localhost, OU=unit, O=org, L=Springfield, ST=MO, C=US
  Algorithm: RSA; Serial number: 0x5485b5a5
  Valid from Mon Dec 08 14:28:53 UTC 2014 until Thu Dec 05 14:28:53 UTC 2024

adding as trusted cert:
  Subject: CN=William Jackson, OU=unit, O=org, L=Springfield, ST=MO, C=US
  Issuer:  CN=William Jackson, OU=unit, O=org, L=Springfield, ST=MO, C=US
  Algorithm: RSA; Serial number: 0x5485b6af
  Valid from Mon Dec 08 14:33:19 UTC 2014 until Sun Mar 08 14:33:19 UTC 2015

trigger seeding of SecureRandom
done seeding SecureRandom

И затем LOT of:

Ignoring unavailable cipher suite: <suite name>
Ignoring unsupported cipher suite: <suite name>

Ответы

Ответ 1

Хорошо - после копания намного больше, я наконец получил эту работу. Огромное спасибо @Dave G и этому учебнику: http://java-notes.com/index.php/two-way-ssl-on-tomcat, из которого пересказывается большинство этих инструкций.

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

  • Создайте сертификат для сервера tomcat. Клиент должен доверять этому сертификату.
  • Создайте хранилище ключей для сервера tomcat и импортируйте в него сертификат сервера.
  • Создайте сертификат для клиента. Сервер должен доверять этому сертификату.
  • Импортировать сертификат клиента в сервер keystore
  • Обновите файл tomcat server.xml с помощью правильного XML-коннектора.

Вышеуказанные шаги необходимы на сервере. После завершения настройки для настройки клиента выполните следующие действия:

  • Скопируйте клиентский сертификат с сервера на клиент.
  • Использовать сертификат клиента при общении с сервером (этот процесс зависит от характера клиентского приложения).

Для конфигурации сертификата я выполнил на серверной машине следующее:

# For the following commands, set the values in parenthesis to be whatever makes sense for your environment.  The parenthesis are not necessary for the command.

# This is an all-in-one command that generates a certificate for the server and places it in a keystore file, while setting both the certifcate password and the keystore password.
# The net result is a file called "tomcat.keystore". 

keytool -genkeypair -alias (serveralias) -keyalg RSA -dname "CN=(server-fqdn),OU=(organizationalunit),O=(organization),L=(locality),ST=(state),C=(country)" -keystore tomcat.keystore -keypass (password) -storepass (password)

# This is the all-in-one command that generates the certificate for the client and places it in a keystore file, while setting both the certificate password and the keystore password.
# The net result is a file called "client.keystore"

keytool -genkeypair -alias (clientalias) -keyalg RSA -dname "CN=(client),OU=(organizationalunit),O=(organization),L=(locality),ST=(state),C=(country)" -keypass (password) -keystore client.keystore -storepass (password) 

# This command exports the client certificate.  
# The net result is a file called "client.cer" in your home directory.

keytool -exportcert -rfc -alias (clientalias) -file client.cer -keypass (password) -keystore client.keystore -storepass (password)

# This command imports the client certificate into the "tomcat.keystore" file.

keytool -importcert -alias (clientalias) -file client.cer -keystore tomcat.keystore -storepass (password) -noprompt

Теперь сертификаты должны быть настроены соответствующим образом. Следующим шагом будет настройка вашего коннектора в tomcat server.xml. Добавьте элемент соединителя, который выглядит так:

<Connector port="8443"
    maxThreads="150"
    scheme="https"
    secure="true"
    SSLEnabled="true"
    truststoreFile="/full/path/to/tomcat.keystore"
    truststorePass="(password)"
    keystoreFile="/full/path/to/tomcat.keystore"
    keystorePass="(password)"
    clientAuth="true"
    keyAlias="serverkey"
    sslProtocol="TLS"/>      

Обратите внимание, что в приведенном выше XML:

  • Атрибут "порт" может быть любым, что вы хотите.
  • Атрибуты "keystoreFile" и "truststoreFile" должны быть полными путями. Tomcat по умолчанию не выглядит в том же каталоге, что и server.xml.
  • Атрибуты "keystorePass" и "truststorePass" должны соответствовать значению (паролю), которое вы использовали при создании файла tomcat.keystore.
  • Атрибут "clientAuth" должен быть установлен на "true". Это то, что инициирует взаимную аутентификацию.

Кроме того, в файле server.xml убедитесь, что у вас НЕ НЕ установлен атрибут AprLifecycleListner. XML для этого слушателя будет выглядеть примерно так:

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

Этот элемент должен быть удален/закомментирован. AprLifecycleListener не настраивается так же, как описано выше, и не будет работать с этими инструкциями.

Перезапустить tomcat. Конфигурация сервера должна быть завершена.

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

Ex: https://mytomcatdomain.com:8443/test

Когда вы это сделаете, вы должны получить стандартное предупреждение от Firefox о ненадежном соединении, потому что мы создали самозаверяющий сертификат для нашего сервера Tomcat. Добавьте исключение для сертификата, чтобы наш клиент (Firefox) доверял нашему серверу (Tomcat).

После того, как вы добавили исключение, вы должны получить сообщение "Безопасное подключение". Код ошибки: "ssl_error_bad_cert_alert". Это подтверждает, что наш сервер Tomcat запрашивает аутентификацию у клиента. Запрос не работает, потому что мы еще не настроили Firefox для отправки нашего доверенного сертификата клиента.

Чтобы настроить Firefox, нам нужно сделать немного больше магии:

// Create a file called DumpPrivateKey.java.  The contents should look like so:
public class DumpPrivateKey {
public static void main(String[] args) throws Exception {
  final String keystoreName = args[0];
    final String keystorePassword = args[1];
    final String alias = args[2];
    java.security.KeyStore ks = java.security.KeyStore.getInstance("jks");
    ks.load(new java.io.FileInputStream(keystoreName), keystorePassword.toCharArray());
    System.out.println("-----BEGIN PRIVATE KEY-----");
    System.out.println(new sun.misc.BASE64Encoder().encode(ks.getKey(alias, keystorePassword.toCharArray()).getEncoded()));
    System.out.println("-----END PRIVATE KEY-----");
  }
}

Скомпилируйте java файл с помощью следующей команды:

javac DumpPrivateKey.java

Теперь мы собираемся использовать эту небольшую утилиту для извлечения ключа из файла client.keystore, который мы создаем выше. Скопируйте файлы client.keystore и client.cer в тот же каталог, что и ваш класс DumpPrivateKey. Выполните следующее:

# This extracts the client key from the client keystore

java DumpPrivateKey client.keystore (password) clientkey > clientkey.pkcs8

# This creates a client.p12 file that can be used by Firefox

openssl pkcs12 -export -in client.cer -inkey clientkey.pkcs8 -password pass:(password) -out client.p12

Обратите внимание, что в приведенном выше коде (пароль) должен быть пароль, который вы использовали для создания client.keystore.

Откройте настройки Firefox. Перейдите на вкладку "Сертификаты". Нажмите кнопку "Просмотреть сертификаты". Перейдите на вкладку "Ваши сертификаты".

Нажмите кнопку "Импорт" и перейдите к файлу "client.p12", который был создан ранее. Вам будет предложено ввести пароль для сертификата клиента.

Предполагая, что "client.p12" был успешно импортирован, теперь вы можете обновить страницу Firefox, и вы должны получить успешный ответ от конечной точки сервера Tomcat.

Ответ 2

@wbj, экспорт PrivateKeyEntry из JKS в PKCS # 12 можно сделать намного проще:

keytool -importkeystore -srckeystore client.keystore -destkeystore client.p12 -deststoretype PKCS12 -srcalias client -deststorepass <password> -destkeypass <password>

Приветствия.

Ответ 3

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

Шаг 1. Создайте свой собственный корневой СА

~/openssl$ mkdir -m 0700 /home/ubuntu/openssl/CA /home/ubuntu/openssl/CA/certs /home/ubuntu/openssl/CA/crl /home/ubuntu/openssl/CA/newcerts /home/ubuntu/openssl/CA/private
~/openssl$ touch /home/ubuntu/openssl/CA/indext.txt
~/openssl$ echo 1000 >> /home/ubuntu/openssl/CA/serial
~/openssl$ mv karun-tomcat-root-ca.key CA/private/

~/openssl$ sudo vi /etc/openssl.cnf
    # Make changes here
    dir = /home/ubuntu/openssl/CA
    #optionally change policy definitions as well
~/openssl$ openssl genrsa -des3 -out karun-tomcat-root-ca.key 2048

  #In below command make sure to use CN=<hostname of your machine>
~/openssl$ openssl req -new -x509 -days 36520 -key karun-tomcat-root-ca.key -out karun-tomcat-root-ca.crt -config openssl.cnf

~$ sudo cp ~/openssl/CA/certs/karun-tomcat-root-ca.crt /usr/share/ca-certificates/

  # make sure in the UI you enable/select the certificate created above
~$ sudo dpkg-reconfigure ca-certificates
  # Now reboot ubuntu machine just to make sure certificates are loaded successfully and tomcat picks it

Шаг 2. Создание пары ключей сервера Tomcat

~$ openssl genrsa -out tomcat-server.key 2048

   # Use common name = <Give IP address>, department = Tomcat Server CSR
~$ openssl req -new -sha256 -config ~/openssl/openssl.cnf -key tomcat-server.key -out tomcat-server.csr
~$ openssl x509 -req -sha256 -days 36520 -in tomcat-server.csr -signkey tomcat-server.key -CA ~/openssl/CA/certs/karun-tomcat-root-ca.crt -CAkey ~/openssl/CA/private/karun-tomcat-root-ca.key -CAcreateserial -out tomcat-server.crt 
~$ openssl pkcs12 -export -name karun-tomcat-server-cert -in tomcat-server.crt -out tomcat-server.p12 -inkey tomcat-server.key -CAfile ~/openssl/CA/certs/karun-tomcat-root-ca.crt -caname karun-root -chain

~$ keytool -importkeystore -destkeystore tomcat-server.jks -srckeystore tomcat-server.p12 -srcstoretype pkcs12 -alias karun-tomcat-server-cert

~$ keytool -import -alias karun-root -keystore tomcat-server.jks -trustcacerts -file ~/openssl/CA/certs/karun-tomcat-root-ca.crt

# **(LATER)** Run this once client cert is generated
~$ keytool -importkeystore -alias karun-tomcat-client-cert -srckeystore ~/client-certs/tomcat-client.p12 -srcstoretype PKCS12 -destkeystore tomcat-server.jks -deststoretype JKS

# **(LATER)** Run this once tomcat server started successfully
~$ openssl s_client -connect localhost:8443 -cert ~/client-certs/tomcat-client.crt -key ~/client-certs/tomcat-client.key -debug -showcerts 

Шаг 3: Создайте парную сторону стороны клиента

~$ openssl genrsa -out tomcat-client.key 2048
  # Use common name = <tomcat-user.xml user say 'admin'>, department = Tomcat Client CSR
~$ openssl req -new -sha256 -config ~/openssl/openssl.cnf -key tomcat-client.key -out tomcat-client.csr
~$ openssl x509 -req -sha256 -days 36520 -in tomcat-client.csr -signkey tomcat-client.key -CA ~/openssl/CA/certs/karun-tomcat-root-ca.crt -CAkey ~/openssl/CA/private/karun-tomcat-root-ca.key -CAcreateserial -out tomcat-client.crt 
~$ openssl pkcs12 -export -name karun-tomcat-client-cert -in tomcat-client.crt -out tomcat-client.p12 -inkey tomcat-client.key -CAfile ~/openssl/CA/certs/karun-tomcat-root-ca.crt -caname karun-root -chain
~$ (optional step) keytool -importkeystore -destkeystore tomcat-client.jks -srckeystore tomcat-client.p12 -srcstoretype pkcs12 -alias karun-tomcat-client-cert
~$ (optional step) keytool -import -alias root -keystore tomcat-client.jks -trustcacerts -file ~/openssl/CA/certs/karun-tomcat-root-ca.crt

Шаг 4: Изменения Tomcat

# Make this change in server.xml of tomcat server
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           keystoreFile="/opt/tomcat/openssl-certs/tomcat-server.jks"
           keystorePass="password"
           keyAlias="karun-tomcat-server-cert"
           truststoreFile="/opt/tomcat/openssl-certs/tomcat-server.jks"
           truststorePass="password"
           clientAuth="true" sslProtocol="TLS" />

Шаг 5: Перезапустите Tomcat Server && проверить журналы, чтобы не допустить ошибок при загрузке

Шаг 6: Загрузите сертификат клиента в браузер

В вашем браузере, например: firefox, перейдите в Настройки → Дополнительно → Сертификат → Просмотр сертификатов → Ваши сертификаты

Импорт "tomcat-client.p12"

https://<tomcat ip>:8443/

Ссылки

http://pages.cs.wisc.edu/~zmiller/ca-howto/

http://www.area536.com/projects/be-your-own-certificate-authority-with-openssl/

Ответ 4

Я бы попытался выполнить следующие шаги

  • Заправьте контейнер, как вы настроили на 8443.
  • Запустите клиентское приложение с помощью -Djavax.net.debug = SSL

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

Это можно сделать намного проще с помощью команды openssl 's_client'

openssl s_client -connect localhost:8443 -showcerts

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

Если сервер не представит список "приемлемых" ЦС, вам придётся сделать несколько магов при создании набора сертификатов.

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

OP добавила дополнительную информацию

Итак, для вас это немного проблема:

---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 263 bytes
---

Две вещи сразу выпрыгивают

  • Сервер не имеет сертификата peer
  • В списке имен CA нет имен

Итак, для (1):

  • убедитесь, что у вашего хранилища ключей на самом деле есть псевдоним "tomcat" в нем с помощью keytool.
  • информация о хранилище/ключевом пароле в tomcat тупой. для удобства, добавьте оба атрибута keystorePassword и keyPassword к вашему коннектору с одинаковыми значениями. Документация для Tomcat 7 указывает, что keystorePass будет по умолчанию использовать keyPass, если он не установлен. Если ваш keyPass и keystorePass имеют одинаковый набор атрибутов keyPass.

Теперь для (2) нам действительно нужно сначала (1) работать, так что заходим и работаем, и мы увидим, где мы находимся в этой точке.