Как загрузить пароль закрытого ключа в новый (не устаревший) 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();