Как запросить URL-адрес, для которого требуется сертификат клиента для аутентификации

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

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

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

Любые предложения?

Ответ 1

Не ясно, какие ограничения вы говорите. В частности, я не уверен, что вы считаете разницей между локальным файлом сертификата и хранилищем ключей. Большинство хранилищ ключей основаны на файлах, поэтому вы можете загрузить этот файл напрямую, без необходимости установки. Являются ли ограничения, связанные с политиками безопасности, используемыми самой 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 эффективно factory для SSLSocketFactory или SSLEngine, и вы можете установить SSLSocketFactory в заданном HttpsURLConnection.

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

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

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

Ответ 2

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

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

keytool -importcert -file mycert -keystore mystore
java -Djavax.net.ssl.keystore=mystore ...