认为我和其他人一样遇到了同样的问题,我一直在经历众多类似的问题和潜在的解决方案,但没有运气。
我正在使用的信任库是cacerts,位于Java 1.6.0 JRE的lib / security中(构建1.6.0_20-b02 ......这可能是问题的根源吗?)。我也尝试过jssecacerts。
使用InstallCert(发布其他类似问题),我可以看到我的证书实际上已安装并且有效(我已删除它,重新导入它等,以确保我看到正确的数据):
java InstallCert <my host name>
Loading KeyStore jssecacerts...
Opening connection to <my host name>:443...
Starting SSL handshake...
No errors, certificate is already trusted
检入keytool和Portecle,重新导入证书(我尝试使用-showcert从openssl生成,从浏览器导出并将其scping过来等)给了我“这已经存在于此处的其他别名下“消息类型。因此,证书进入工具的方式似乎没有任何问题。
在代码中强制显式trustStore路径没有任何区别,在所有情况下,当我打开调试(通过javax.net.debug的setProperty到“all”)时我最终看到的是:
main, SEND TLSv1 ALERT: fatal, description = certificate_unknown
main, WRITE: TLSv1 Alert, length = 2 [Raw write]: length = 7 0000: 15
03 01 00 02 02 2E ....... main, called
closeSocket() main, handling exception:
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
不幸的是,我不能通过实现我自己的TrustManager来覆盖检查 - 它必须实际检查。
我从主机获得的证书有许多扩展名(准确地说是9),这让我想知道他们是否是这个问题的一部分。
我还可以检查/尝试什么?切换到不同的JRE版本?
答案 0 :(得分:0)
我猜这些事情都发生了:
a)您在Web服务器上运行代码。他们经常使用自己的信任存储 - 所以你真的确定在代码执行时使用的是cacerts
吗?
b)默认情况下,Java会尝试通过下载和解释CRL来检查证书的有效性。如果您在代理后面,则下载失败,因此整个PKIX检查将失败。
答案 1 :(得分:0)
SSL调试跟踪将显示您正在使用的cacerts文件,只要您不自己手动加载它。显然你没有使用你认为的那个。
答案 2 :(得分:0)
您仍然可以通过实施自己的信任管理器来检查证书。我遇到了类似的问题here。我也尝试将证书添加到cacerts
,但无济于事。
在您的信任管理器中,您需要显式加载证书。基本上我必须做的是这样的事情:
首先,我创建一个使用实际证书文件的信任管理器:
public class ValicertX509TrustManager implements X509TrustManager {
X509TrustManager pkixTrustManager;
ValicertX509TrustManager() throws Exception {
String valicertFile = "/certificates/ValicertRSAPublicRootCAv1.cer";
String commwebDRFile = "/certificates/DR_10570.migs.mastercard.com.au.crt";
String commwebPRODFile = "/certificates/PROD_10549.migs.mastercard.com.au.new.crt";
Certificate valicert = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(valicertFile));
Certificate commwebDR = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebDRFile));
Certificate commwebPROD = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebPRODFile));
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, "".toCharArray());
keyStore.setCertificateEntry("valicert", valicert);
keyStore.setCertificateEntry("commwebDR", commwebDR);
keyStore.setCertificateEntry("commwebPROD", commwebPROD);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
trustManagerFactory.init(keyStore);
TrustManager trustManagers[] = trustManagerFactory.getTrustManagers();
for(TrustManager trustManager : trustManagers) {
if(trustManager instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) trustManager;
return;
}
}
throw new Exception("Couldn't initialize");
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
pkixTrustManager.checkServerTrusted(chain, authType);
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
pkixTrustManager.checkServerTrusted(chain, authType);
}
public X509Certificate[] getAcceptedIssuers() {
return pkixTrustManager.getAcceptedIssuers();
}
}
现在,使用此信任管理器,我必须创建一个套接字工厂:
public class ValicertSSLProtocolSocketFactory implements ProtocolSocketFactory {
private SSLContext sslContext = null;
public ValicertSSLProtocolSocketFactory() {
super();
}
private static SSLContext createValicertSSLContext() {
try {
ValicertX509TrustManager valicertX509TrustManager = new ValicertX509TrustManager();
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new ValicertX509TrustManager[] { valicertX509TrustManager}, null);
return context;
}
catch(Exception e) {
Log.error(Log.Context.Net, e);
return null;
}
}
private SSLContext getSSLContext() {
if(this.sslContext == null) {
this.sslContext = createValicertSSLContext();
}
return this.sslContext;
}
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException {
return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
}
public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException {
if(params == null) {
throw new IllegalArgumentException("Parameters may not be null");
}
int timeout = params.getConnectionTimeout();
SocketFactory socketFactory = getSSLContext().getSocketFactory();
if(timeout == 0) {
return socketFactory.createSocket(host, port, localAddress, localPort);
}
else {
Socket socket = socketFactory.createSocket();
SocketAddress localAddr = new InetSocketAddress(localAddress, localPort);
SocketAddress remoteAddr = new InetSocketAddress(host, port);
socket.bind(localAddr);
socket.connect(remoteAddr, timeout);
return socket;
}
}
public Socket createSocket(String host, int port) throws IOException {
return getSSLContext().getSocketFactory().createSocket(host, port);
}
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}
public boolean equals(Object obj) {
return ((obj != null) && obj.getClass().equals(ValicertSSLProtocolSocketFactory.class));
}
public int hashCode() {
return ValicertSSLProtocolSocketFactory.class.hashCode();
}
}
然后我刚刚注册了一个新协议:
Protocol.registerProtocol("vhttps", new Protocol("vhttps", new ValicertSSLProtocolSocketFactory(), 443));
PostMethod postMethod = new PostMethod(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue()));
}
HttpClient client = new HttpClient();
int status = client.executeMethod(postMethod);
if (status == 200) {
StringBuilder resultBuffer = new StringBuilder();
resultBuffer.append(postMethod.getResponseBodyAsString());
return new HttpResponse(resultBuffer.toString(), "");
} else {
throw new IOException("Invalid response code: " + status);
}
唯一的缺点是我必须为此特定证书创建特定协议(vhttps
)。