gpt4 book ai didi

java - 如何检索不受信任的 SSL 服务器证书以查看和信任它?

转载 作者:搜寻专家 更新时间:2023-10-31 08:20:41 25 4
gpt4 key购买 nike

我的问题:

我想连接到服务器(不限于 HTTPS 协议(protocol)——可以是 LDAP-over-SSL,可以是 SMTPS,可以是 IMAPS 等)可能使用 Java 默认情况下不信任的证书(因为它们是自签名的)。

所需的工作流是尝试连接,检索证书信息,将其呈现给用户,如果他接受,则将其添加到信任库中,以便以后得到信任。

我在检索证书时卡住了。我有代码(见文章末尾),我从这里和关于 java SSL 的问题的答案指向的网站抄袭。该代码只是创建一个 SSLSocket,启动 SSL 握手,并向 SSL session 请求 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");
}
}
}
}
}

最佳答案

您可以执行此操作,实现一个接受所有证书的临时 TrustManager 和一个验证所有名称的临时 HostnameVerifier(显然,您必须仅使用它们来检索证书和不要发送私有(private)数据)。

以下代码从任意 https url 检索证书并将它们保存到文件中:

URL url = new URL("https://<yoururl>");

SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(null, new TrustManager[]{ new X509TrustManager() {

private X509Certificate[] accepted;

@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}

@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
accepted = xcs;
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return accepted;
}
}}, null);

HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

connection.setHostnameVerifier(new HostnameVerifier() {

@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});

connection.setSSLSocketFactory(sslCtx.getSocketFactory());

if (connection.getResponseCode() == 200) {
Certificate[] certificates = connection.getServerCertificates();
for (int i = 0; i < certificates.length; i++) {
Certificate certificate = certificates[i];
File file = new File("/tmp/newcert_" + i + ".crt");
byte[] buf = certificate.getEncoded();

FileOutputStream os = new FileOutputStream(file);
os.write(buf);
os.close();
}
}

connection.disconnect();

关于java - 如何检索不受信任的 SSL 服务器证书以查看和信任它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10577029/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com