【发布时间】:2012-05-21 13:34:16
【问题描述】:
我的问题:
我想连接到可能使用 Java 默认不信任的证书的服务器(不限于 HTTPS 协议——可以是 LDAP-over-SSL、可以是 SMTPS、可以是 IMAPS 等)(因为它们是自签名的)。
所需的工作流程是尝试连接,检索证书信息,将其呈现给用户,如果他接受,则将其添加到信任库,以便继续信任它。
我在检索证书时遇到了困难。我有代码(见文章末尾),这些代码是我从这里和从回答有关 java SSL 的问题所指向的站点中抄来的。该代码只是创建了一个SSLSocket,启动SSL 握手,然后向SSL 会话询问Certificate[]。当我使用已经可信任的证书连接到服务器时,代码可以正常工作。但是当我使用自签名证书连接到服务器时,我得到了通常的结果:
Exception in thread "main" 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
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
[etc]
如果我使用 -Djavax.net.debug=all 运行,我看到 JVM 确实检索了自签名证书,但会在到达返回证书的地步之前破坏使用不受信任的证书的连接。
似乎是先有鸡还是先有蛋的问题。它不会让我看到证书,因为它们不受信任。但是我需要查看证书才能将它们添加到信任库中,以便它们受到信任。你是如何摆脱这种局面的?
例如,如果我将程序运行为:
java SSLTest www.google.com 443
我得到一份 Google 正在使用的证书的打印输出。但是如果我运行它
java SSLTest my.imap.server 993
我得到了上面提到的异常。
代码:
import java.io.InputStream;
import java.io.OutputStream;
import java.security.cert.*;
import javax.net.SocketFactory;
import javax.net.ssl.*;
public class SSLTest
{
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("Usage: SSLTest host port");
return;
}
String host = args[0];
int port = Integer.parseInt(args[1]);
SocketFactory factory = SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.startHandshake();
Certificate[] certs = socket.getSession().getPeerCertificates();
System.out.println("Certs retrieved: " + certs.length);
for (Certificate cert : certs) {
System.out.println("Certificate is: " + cert);
if(cert instanceof X509Certificate) {
try {
( (X509Certificate) cert).checkValidity();
System.out.println("Certificate is active for current date");
} catch(CertificateExpiredException cee) {
System.out.println("Certificate is expired");
}
}
}
}
}
【问题讨论】:
标签: java ssl ssl-certificate