почему Java не отправляет сертификат клиента во время подтверждения SSL?

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

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

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

В частности:

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

Мои вопросы:

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

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

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

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

Чтобы узнать, в каком ключевом псевдониме есть закрытый ключ, используйте keytool -list -keystore store.jks (здесь я предполагаю тип магазина keytool -list -keystore store.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 

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

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

  • Почему OS X не доверяет SSL-сертификату GitHub?
  • Запрос Python, бросающий SSLError
  • Доверяйте всем сертификатам, используя HttpClient over HTTPS
  • как добавить терминологическое имя объекта в ssl certs?
  • HTTP-HTTPS-туннель
  • Отключить SSLv3 в основных браузерах
  • Добавить постоянное исключение SSL-сертификата в Chrome (Linux)
  • Как создать самозаверяющий сертификат для доменного имени для разработки?
  • Как создать сервер HTTPS в Node.js?
  • По умолчанию SecurityProtocol в .NET 4.5
  • HTTPS с NSURLConnection - NSURLErrorServerCertificateUntrusted
  • Давайте будем гением компьютера.