Как загрузить пароль закрытого ключа в новый (не устаревший) SSLSocketFactory?

Мой текущий TCP-клиент создает сокеты, используя org.apache.http.conn.ssl.SSLSocketFactory
Я перехожу на import javax.net.ssl.SSLSocketFactory;Однако я не уверен, как загрузить закрытый ключ для сертификата клиента, который хранится в файле.p12, который у меня уже есть, в качестве контекста для нового SSLSocketFactory?

Вот мой существующий код с использованием устаревшего SSLSocketFactory:

import org.apache.http.ssl.SSLContexts;
import org.apache.http.conn.ssl.SSLSocketFactory;

String ksPassphrase = "myKSpass";
String pkPassphrase = "myPKpass";
// Get a keystore instance of type PKCS12:
KeyStore keystore = KeyStore.getInstance("PKCS12");
// Load keystore file and password:
keystore.load(new FileInputStream("myFile.p12"), ksPassphrase.toCharArray());
// Create HTTPS connection socket factory context:
SSLContext context = SSLContexts.custom()
    .loadKeyMaterial(keystore, pkPassphrase.toCharArray())
    .build();

SSLSocketFactory sslScktFactory = new SSLSocketFactory(context);

Вот лучший код, которым я мог управлять из документации:

import javax.net.ssl.*;

// not sure if this is the pass to KS or private key or, somehow both?
String passphrase = "myPassphrase" 

SSLContext context = SSLContext.getInstance("TLS");
KeyManagerFactory keyMngFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");

keyStore.load(new FileInputStream("myFile.jks"), passphrase.toCharArray());
keyMngFactory.init(keyStore, passphrase);
context.init(keyMngFactory.getKeyManagers(), null, null);

SSLSocketFactory sslScktFactory = context.getSocketFactory();
  • Думаю, проблема в том, что у меня нет .custom()для контекста в новой библиотеке.
    Что использовать для нового SSLSocketFactory?
  • Дело в том, что хранилища ключей JKS не имеют внутренних паролей для закрытых ключей, хранящихся внутри (до сих пор я использовал только PKCS, не знаком с форматом JKS), и поэтому я не могу видеть, где указывается пароль закрытого ключа к?

1 ответ

Решение

Пароль, который вы передаете KeyStore.load(InputStream,char[])пароль магазина; пароль, который вы передаетеKeyManagerFactory.init(KeyStore,char[]) является паролем частного ключа (единственное число; должно быть одинаковым для всех ключей, если их больше одного), и обратите внимание, что это char[] не String- ваш компилятор (или IDE) должен был вам это сказать. Вам нужно изменить свой новый код, чтобы использоватьKeyStore.getInstance("PKCS12") если вы хотите продолжить использование существующих (или любых других / новых) файлов PKCS12.

Обратите внимание, что API позволяет использовать keypass, отличный от storepass, но другое программное обеспечение, с помощью которого вы, возможно, захотите обмениваться файлами PKCS12 (например, Windows, MacOSX, OpenSSL, я думаю, NSS), не поддерживает это, и старайтесь избегать такие проблемы командная строка Javakeytoolне будет устанавливать keypass, отличный от storepass для PKCS12.

Что использовать для нового SSLSocketFactory?

SSLContext.getSocketFactory()- именно так, как вы написали. Фактически, это то, что было вашим предыдущим, устаревшимorg.apache.http.conn.ssl.SSLSocketFactory.SSLSocketFactory(SSLContext) работает внутренне, за исключением того, что по умолчанию также используется HostNameVerifier.

Дело в том, что хранилища ключей JKS не имеют внутренних паролей для закрытых ключей, хранящихся внутри (до сих пор я использовал только PKCS, не знаком с форматом JKS), и поэтому я не вижу, куда передается пароль закрытого ключа к?

Нет; У хранилищ JKS есть отдельные storepass и keypass, которые использовались бы в опубликованном вами коде, если бы он был исправлен, как я описал выше, - хотя шифрование с закрытым ключом JKS использует keypass для более слабого, чем тот, который обычно используется в PKCS12. А поскольку файлы JKS в любом случае несовместимы с другим программным обеспечением,keytoolподдерживает ли keypass, отличный от storepass. по фактуkeytool (и JCA в целом) поддерживает использование разных значений keypass для разных частных ключей в одном хранилище JKS, но KeyManagerFactory(для SSL/TLS, то есть JSSE) не поддерживает это, как и Apache (который, кроме добавления / упаковки стратегии выбора ключа, просто использует JSSE ниже).

(OP) Изменить: вот несколько проверенных рабочих кодов, полученных в результате вашего предложения:

// Consider having both the same, for compatibility with Windows/MacOSX/OpenSSL/etc:
String ksPassphrase = "myKSpass";
String pkPassphrase = "myPKpass";

SSLContext context = SSLContext.getInstance("TLS");
KeyManagerFactory keyMngFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");

keyStore.load(new FileInputStream("myFile.p12"), 
ksPassphrase.toCharArray());
keyMngFactory.init(keyStore, pkPassphrase.toCharArray());
context.init(keyMngFactory.getKeyManagers(), null, null);

SSLSocketFactory sslScktFactory = context.getSocketFactory();
Другие вопросы по тегам