Вы не можете разделить хранилище ключей между клиентом и сервером, потому что хранилище ключей содержит закрытый ключ. При аутентификации клиент пропускает сертификаты с закрытыми ключами. Как сказано выше, вам необходимо развернуть склад доверенных сертификатов на стороне клиента.
Сертификаты в хранилище ключей ведут себя не одинаково, в зависимости от того, как вы их сгенерировали или импортировали.
Тип записи импортированного сертификата (видимый при подробном перечислении всего хранилища ключей с помощью -list -v
) - "rustCertEntry ". Тип записи сгенерированного сертификата - «PrivateKeyEntry». При экспорте сертификата вы экспортируете только его открытый ключ и необязательную ссылку на его издателя.
Похоже, вам нужно экспортировать самоподписанный сертификат в хранилище ключей в качестве доверенного сертификата в хранилище доверенных сертификатов (здесь имена имеют смысл).
Я бы не стал этого делать, потому что реализации SSL / TLS, вероятно, не поддерживают это. С точки зрения реального мира это похоже на развертывание секретного секретного ключа от Verisign на каком-то непонятном веб-сервере для подписи случайных страниц, тогда как единственная цель этого закрытого ключа - оставаться в безопасности и подписывать другие сертификаты. Разработчики SSL / TLS, вероятно, не будут загрязнять свой код таким случаем использования, и в любом случае расширение сертификата «KeyUsage» может ограничить использование сертификата подписью, предотвращая шифрование.
Именно поэтому я предлагаю перестроить цепочку сертификатов для вашего теста.
Документация keytool содержит интересную часть о создании цепочки (команда -gencert
), но это очень скелетный пример, который не охватывает отношения хранилище ключей и хранилища доверенных сертификатов. Я улучшил его, чтобы имитировать сторонний центр сертификации.
Временное хранилище their-keystore.jks
представляет центр выдачи сертификатов. Я передаю его цепочкой сертификатов ca2 -> ca1 -> ca
, а ca
считается корневым сертификатом. Цепочка появляется с каждым некорневым сертификатом (а именно ca1
и ca2
), ссылаясь на их эмитента как Certificate[2]
. Обратите внимание, что каждый сертификат «PrivateKeyEntry».
Затем я подаю my-keystore.jks
с этими сертификатами в следующем порядке: ca
, ca1
, ca2
. Я импортирую ca
с параметром -trustcacerts
, что означает, что он становится корневым сертификатом. В my-keystore.jks
каждый импортируемый сертификат теперь называется «rustCertEntry », что означает, что существует только открытый ключ. Отношение выдачи отображается только в поле «Эмитент», но оно в порядке, поскольку отношение доверия имело наибольшее значение во время импорта.
На данный момент my-keystore.jks
имитирует среду, содержащую некоторые доверенные сертификаты, например, свежую JRE. their-keystore.jks
имитирует владельцев тех сертификатов, которые имеют право подписывать запросы сертификатов.
Я тоже: я создаю самоподписанный сертификат e1
в my-keystore.jks
, получаю его подписанным ca2
(через their-keystore.jks
) и импортирую подписанный результат обратно в my-keystore.jks
. e1
по-прежнему является «PrivateKeyEntry» (потому что его закрытый ключ остается в my-keystore.jks
), но теперь я построил следующую цепочку: e1 -> ca2 -> ca1
. Кажется, что ca1 -> ca
подразумевается, когда ca
является центром сертификации.
Для создания хранилища доверенных сертификатов я просто импортирую сертификаты ca
, ca1
и ca2
так же, как я делал для my-keystore.jks
. Обратите внимание, что я не импортирую e1
, так как я ожидаю, что клиент SSL / TLS проверит его по ca2
.
Я думаю, это довольно близко к тому, как все работает в реальном мире. Что здесь хорошо, так это то, что вы имеете полный контроль над сертификатами и не зависите от JRE.
Вот код, демонстрирующий то, что я говорю на практике. Кажется, работает с Jetty (клиент и сервер), пока вы отключите список отзыва сертификатов (тема оставлена на другой день).
#!/bin/bash
rm their-keystore.jks 2> /dev/null
rm my-keystore.jks 2> /dev/null
rm my-truststore.jks 2> /dev/null
echo "===================================================="
echo "Creating fake third-party chain ca2 -> ca1 -> ca ..."
echo "===================================================="
keytool -genkeypair -alias ca -dname cn=ca \
-validity 10000 -keyalg RSA -keysize 2048 \
-ext BasicConstraints:critical=ca:true,pathlen:10000 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -genkeypair -alias ca1 -dname cn=ca1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -genkeypair -alias ca2 -dname cn=ca2 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -certreq -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca \
-ext KeyUsage:critical=keyCertSign \
-ext SubjectAlternativeName=dns:ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
#echo "Debug exit" ; exit 0
keytool -certreq -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca1 \
-ext KeyUsage:critical=keyCertSign \
-ext SubjectAlternativeName=dns:ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore their-keystore.jks
echo "===================================================================="
echo "Fake third-party chain generated. Now generating my-keystore.jks ..."
echo "===================================================================="
read -p "Press a key to continue."
# Import authority's certificate chain
keytool -exportcert -alias ca \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -trustcacerts -noprompt -alias ca \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca2 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
# Create our own certificate, the authority signs it.
keytool -genkeypair -alias e1 -dname cn=e1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -certreq -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca2 \
-ext SubjectAlternativeName=dns:localhost \
-ext KeyUsage:critical=keyEncipherment,digitalSignature \
-ext ExtendedKeyUsage=serverAuth,clientAuth \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-keystore.jks
echo "================================================="
echo "Keystore generated. Now generating truststore ..."
echo "================================================="
read -p "Press a key to continue."
keytool -exportcert -alias ca \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -trustcacerts -noprompt -alias ca \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca1 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca2 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca2 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-truststore.jks
rm their-keystore.jks 2> /dev/null