私の問題:
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");
}
}
}
}
}