通过HTTPS / SSL的Java客户端证书
我正在使用Java 6,并试图使用客户端证书针对远程服务器创建HttpsURLConnection
。
服务器正在使用自签名根证书,并要求提供受密码保护的客户端证书。 我已将服务器根证书和客户机证书添加到我在/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/security/cacerts
10.5)中找到的默认Java密钥库。 密钥库文件的名称似乎表明客户端证书不应该进入那里?
无论如何,将根证书添加到此商店解决了臭名昭着的javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed' problem.
但是,我现在坚持如何使用客户端证书。 我尝试了两种方法,但都没有把我带到任何地方。
首先,首选,请尝试:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://somehost.dk:3049");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
// The last line fails, and gives:
// javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
我尝试过跳过HttpsURLConnection类(因为我想与服务器交谈HTTP而不理想),并且改为执行此操作:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("somehost.dk", 3049);
InputStream inputstream = sslsocket.getInputStream();
// do anything with the inputstream results in:
// java.net.SocketTimeoutException: Read timed out
我甚至不确定客户端证书是否是这里的问题。
最后解决了它)。 在这里得到了强烈的暗示(甘道夫斯的回答也触及了一下)。 缺失的链接(主要)是下面的第一个参数,并且在某种程度上我忽略了密钥库和信任库之间的差异。
自签名服务器证书必须导入到信任库中:
keytool -import -alias gridserver -file gridserver.crt -storepass $ PASS -keystore gridserver.keystore
需要设置这些属性(在命令行或代码中):
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS
工作示例代码:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://gridserver:3049/cgi-bin/ls.py");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println("Received " + string);
}
虽然不推荐,但您也可以一起禁用SSL证书验证:
import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class SSLTool {
public static void disableCertificateValidation() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}};
// Ignore differences between given hostname and certificate hostname
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) { return true; }
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception e) {}
}
}
您是否设置了KeyStore和/或TrustStore系统属性?
java -Djavax.net.ssl.keyStore=pathToKeystore -Djavax.net.ssl.keyStorePassword=123456
或者与代码一起使用
System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);
与javax.net.ssl.trustStore一样
链接地址: http://www.djcxy.com/p/31151.html