2012-02-15 2 views
49

Я пытаюсь подключиться к безопасному веб-сервису.Почему Java не отправляет сертификат клиента во время подтверждения SSL?

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

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

В частности:

  1. Сервер запросил сертификат клиента (CN = ROOTCA) - т.е. «дать мне сертификат, подписанный корневой ЦС»
  2. Java посмотрел в хранилище ключей и только нашел свой клиент сертификат, подписанный «SubCA», который, в свою очередь, выдается «RootCA». Он не потрудился заглянуть в траст-магазин ... duh OK Я думаю,
  3. К сожалению, когда я попытался добавить сертификат «SubCA» в хранилище ключей, это совсем не помогло. Я проверил, загружены ли сертификаты в хранилище ключей. Они делают, но KeyManager игнорирует все сертификаты, кроме клиентского.
  4. Все выше, приводит к тому, что Java решает его не имеет каких-либо сертификатов, которые удовлетворяют запрос сервера и отправляет ничего ... tadaaa отказ квитирования :-(

Мои вопросы:

  1. Возможно ли, что я добавил сертификат «SubCA» в хранилище ключей таким образом, чтобы «сломал цепочку сертификатов» или что-то еще, чтобы KeyManager загружал только клиентский сертификат и игнорировал остальные? (Chrome и openssl справляются с цифрой что почему я не могу java? - обратите внимание, что сертификат «SubCA» всегда представляется отдельно как доверенный орган, поэтому Chrome appare ntly правильно упаковывает его вместе с сертификатом клиента во время рукопожатия)
  2. Является ли это официальной «проблемой конфигурации» на стороне сервера? Сервер является третьим лицом. Я ожидаю, что сервер запросит сертификат, подписанный органом «SubCA», поскольку это то, что они нам предоставили. Я подозреваю, что тот факт, что это работает в Chrome и openssl, заключается в том, что они «менее ограничительные», а java просто «по книге» и не удается.

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

+2

Следует добавить к ответу @ Bruno, что основная причина заключается в том, что был закрытый ключ, но не соответствующий сертификат (т. Е. С тем же псевдонимом), поэтому Java не мог отправить его, когда его спрашивали сообщения «CertificateRequest». Другие причины этого могут не включать сертификат, подписанный эмитентами, указанным сервером, или сертификаты, соответствующие шифрам, указанным сервером. – EJP

+0

Мы решили эту проблему, просто сопоставив шифры, указанные сервером. Спасибо вам, ребята, за всю эту информацию, это было очень полезно. –

ответ

76

Возможно, вы могли импортировать промежуточный сертификат ЦС в хранилище ключей, не связывая его с записью, в которой у вас есть сертификат клиента и его закрытый ключ. Вы должны увидеть это, используя keytool -v -list -keystore store.jks. Если вы получаете только один сертификат на запись псевдонима, они не вместе.

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

Чтобы узнать, у кого есть пароль, введите keytool -list -keystore store.jks (здесь я использую тип магазина JKS). Это скажет вам что-то вроде этого:

Your keystore contains 1 entry 

myalias, Feb 15, 2012, PrivateKeyEntry, 
Certificate fingerprint (MD5): xxxxxxxx 

Здесь псевдоним myalias. Если вы используете -v, вы должны увидеть Alias Name: myalias.

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

keytool -exportcert -rfc -file clientcert.pem -keystore store.jks -alias myalias 

Это должно дать вам файл PEM.

Используя текстовый редактор (или cat), подготовьте файл (давайте назовем его bundle.pem) с этим сертификатом клиента и промежуточным сертификатом ЦС (и, возможно, самим сертификатом корневого ЦС, если вы хотите), чтобы клиент-сертификат в начале, и его сертификат эмитента находится чуть ниже.

Это должно выглядеть следующим образом:

-----BEGIN CERTIFICATE----- 
MIICajCCAdOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJVSzEa 
.... 
-----END CERTIFICATE----- 
-----BEGIN CERTIFICATE----- 
MIICkjCCAfugAwIBAgIJAKm5bDEMxZd7MA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV 
.... 
-----END CERTIFICATE----- 

Теперь импорт этого расслоения вместе в псевдониме, где секретный ключ:

keytool -importcert -keystore store.jks -alias myalias -file bundle.pem 
+1

Thanx миллион Бруно - это сработало. Я думаю, что это может быть немного более документировано. Я просто провел несколько дней, пытаясь понять, что, черт возьми, происходит. Намеки Java практически не существовали. –

+1

Мне тоже нужно объединить сертификат и закрытый ключ в импорте, но я начинаю с файла сертификата * .pem (начинается с «----- BEGIN CERTIFICATE -----») и * .key секретный ключ («----- НАЧАТЬ ЧАСТНЫЙ КЛЮЧ RSA -----»). Я попытался объединить их, а затем импортировать, но я получил: keytool error: java.lang.Exception: введите не сертификат X.509. Любые идеи, в которых я ошибаюсь? Я читал в http://stackoverflow.com/questions/5297867/ssl-tomcat-certificate-error/11984173#11984173, который, возможно, потребуется преобразовать в тип ключа pkcs12. Есть идеи? Я застрял! Спасибо. –

+0

Спасибо Бруно, ты спас мой день !!! – Gaucho

5

В дополнение здесь, вы можете использовать %> openssl s_client -connect host.example.com:443 и см. дамп и проверьте, что весь основной сертификат действителен для клиента. Вы ищете это в нижней части вывода. Проверьте код возврата: 0 (КИ)

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

+0

, в какую команду вы использовали '-showcerts'? –

+0

@JerylCook 'openssl s_client -showcerts -connect host.example.com: 443' – Sky

Смежные вопросы