Как запросить URL, который требует клиентский сертификат для аутентификации - PullRequest
15 голосов
/ 17 сентября 2010

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

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

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

Есть предложения?

Ответы [ 2 ]

23 голосов
/ 17 сентября 2010

Не ясно, о каких ограничениях вы говорите. В частности, я не уверен, что вы считаете разницу между локальным файлом сертификата и хранилищем ключей. Большинство хранилищ ключей основаны на файлах, поэтому вы можете загрузить этот файл напрямую, без необходимости установки. Связаны ли ограничения с политиками безопасности, используемыми самой JVM (что может помешать вам создавать KeyStore s)?

Во-первых, вам нужен не только сертификат на стороне клиента, но и его закрытый ключ. Часто люди используют слово «сертификат» в этом контексте, чтобы обозначать и то и другое, но вам нужно убедиться, что ваш файл не содержит сертификат без закрытого ключа. Как правило, вы найдете комбинацию секретный ключ + сертификат в файле PKCS # 12 (.p12 / .pfx), множество инструментов для импорта / экспорта в этом формате; это также формат хранилища ключей, изначально поддерживаемый Sun JVM (тип PKCS12).

Чтобы это работало, вам нужно настроить соединение с соответствующим хранилищем ключей. Проверка подлинности клиента-сертификата SSL / TLS всегда инициируется сервером: клиент отвечает сертификатом, если он есть (и хочет его использовать). Чтобы настроить его для определенного URL-адреса, вам необходимо выяснить, из-за чего устанавливается соединение (возможно, HttpsURLConnection), и установить его там (если оно не настроено в контексте по умолчанию - даже если оно настроено в контексте по умолчанию, оно будет использоваться только для серверов, которые его запрашивают).

Чтобы настроить хранилище ключей глобально на JVM (что может быть тем, что вам мешают делать ваши ограничения), вы можете установить системные свойства javax.net.ssl.keyStore javax.net.ssl.keyStorePassword (и связанные с ними). (Поскольку пароль может быть виден, лучше не делать это в командной строке).

Эти системные свойства используются для конфигурации по умолчанию SSLContext (которая часто используется прозрачно для библиотек или классов, таких как HttpsURLConnection, для построения SSLSocketFactory, а затем SSLSocket, инициализированных этими свойствами ).

Вы можете собрать SSLContext из вашего файла специально для использования для этого соединения. SSLContext фактически является фабрикой для SSLSocketFactory или SSLEngine, и вы можете установить SSLSocketFactory в данном HttpsURLConnection.

Следующее создаст SSLContext с использованием "/path/to/file.p12" в качестве хранилища ключей (то есть с вашим закрытым ключом и сертификатом, который вы собираетесь отправить) и сохранит настройки по умолчанию для хранилище доверенных сертификатов (вам также нужно перехватить исключение для входного потока).

KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream("/path/to/file.p12");
ks.load(fis, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "password".toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);

Оттуда вы можете настроить соединение следующим образом (если это то, что вы используете):

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection instanceof HttpsURLConnection) {
    ((HttpsURLConnection)connection)
         .setSSLSocketFactory(sc.getSSLSocketFactory());
}

Некоторые библиотеки позволяют вам передавать SSLContext напрямую (Apache HTTP Client 4 поддерживает это, и это можно сделать с помощью Apache HTTP Client 3 , используя это .)

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

Возможно, эта библиотека могла бы помочь (но это не обязательно): вы могли бы использовать KeystoreLoader для ее помощников, чтобы сделать это. В этих библиотеках также есть SSLContextFactories (но вам, вероятно, не понадобятся никакие из оболочек, так как они предназначены для настройки доверительного управления или выбора ключа).

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

1 голос
/ 17 сентября 2010

Вы можете изменить хранилище ключей JSSE по умолчанию через свойство при вызове приложения, -Djavax.net.ssl.keystore=somefile.

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

keytool -importcert -file mycert -keystore mystore
java -Djavax.net.ssl.keystore=mystore ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...