我很新的SSL和坦率地说,我发现实现是相当混乱,所以很抱歉,如果我的问题似乎毫无头绪或小康基地。
所以我有一个SSL套接字服务器使用自签名证书的形式的p12文件。我想有一个客户端套接字能够连接到这个服务器,而无需访问私钥。然而,我希望客户端能够验证服务器不是冒名顶替者,并有私钥。
我的问题是,我似乎不能创建一个SSLContext,因此,一个SSLSocketFactory使用任何东西以外的p12文件。理想情况下,我会创建我的SSLSocketFactory使用证书根文件。
这里的方式我有我的客户端设置:
public class SSLClient {
private static final String TLS_VERSION = "TLSv1.2";
public static void run(int serverPort, String certName, char[] certPass) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream certInputStream = TLSClient.class.getResourceAsStream("/" + certName);
trustStore.load(certInputStream, certPass);
certInputStream.close();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keyStoreInputStream = TLSClient.class.getResourceAsStream("/" + certName);
keyStore.load(keyStoreInputStream, certPass);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, certPass);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), SecureRandom.getInstanceStrong());
SocketFactory factory = sslContext.getSocketFactory();
try (Socket connection = factory.createSocket("localhost", serverPort)) {
((SSLSocket) connection).setEnabledProtocols(new String[] {TLS_VERSION});
SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
((SSLSocket) connection).setSSLParameters(sslParams);
BufferedReader input = new BufferedReader(new InputStreamReader(connection.getInputStream()));
System.out.println(input.readLine());
new PrintWriter(connection.getOutputStream(),true).println("client reply");
}
}
}
字符串
我尝试使用根证书(.crt)和PEM文件,但它们都给我一个输入流错误给予:
Exception in thread "main" java.io.IOException: toDerInputStream rejects tag type 45
at java.base/sun.security.util.DerValue.toDerInputStream(DerValue.java:1155)
at java.base/sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2013)
at java.base/sun.security.util.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:221)
at java.base/java.security.KeyStore.load(KeyStore.java:1473)
at TLSClient.run(TLSClient.java:16)
at Main.main(Main.java:12)
型
我目前的方法/解决方案:我使用服务器根证书为客户端创建了一个“空”p12文件。这似乎是预期的工作.这样做有问题吗?
使用:
openssl pkcs12 -export -in myCert.crt -out myCertPks.p12 -name alias
2条答案
按热度按时间qyzbxkaa1#
如果要专门使用Java SSLContext,可以使用直接信任指定证书的自定义TrustManager。
字符串
然后使用创建的TrustManager创建SSLContext,
型
oalqel3c2#
一种简单的方法是将受信任的CA公共证书导入Java密钥库中(您可以使用
keytool
(随Java提供的CLI工具)操作它们)。如果您使用
JAVA_HOME
的子文件夹中的文件 * caccounts *,JVM将自动识别它。你可以在JDK的tool docs中找到关于
keytool
的文档(链接到Java 21,但版本可能不是那么相关)。这里还记录了关于 * caccounts * 文件的确切位置,默认密码等的更好描述。通过这种方式,您不必在
KeyStore
,TrustManager
等周围捣乱,只需使用默认的SSLSocketFactory
创建SSLSocket
,就可以了。