証明書のホスト名/CNがURLのホスト名と一致するかどうかを確認する関数を書いています。
私の設定: Javaが提供する デフォルトのSSLSocketを使用しています。SSLSocketにHandshakeCompletedListenerを追加しました。(これは私が解決策を提案しているだけです。ハンドシェイクが完了した後に証明書を検証するための最良の方法ではないと思います)
私の難問:https ://gmail.com、つまりホスト:gmail.comポート:443 over ssl に接続すると、CN=mail.google.comの証明書を取得します。ホスト名検証機能はこの証明書を拒否し、接続を閉じます。
不思議なことに、広く使用されているブラウザは同じことをしません。「証明書は信頼されていません。続行しますか?」という通常のメッセージは表示されません。どういうわけか、URLのホスト名と一致していなくても、提示された証明書をすべて信頼しています。
では、証明書を完全に拒否しないように、ブラウザは何をしているのでしょうか。証明書が途中で有効になるようにするために、どのような追加の手順を実行していますか?つまり、一連のリダイレクトの後、 https://gmail.comはhttps://mail.google.comに置き換えられ、証明書はCN = mail.google.comと一致するため、問題なく検証されます。このメカニズムの背後にある特定のルールはありますか?
ご意見をお聞かせください。:)
編集:ホスト/ピアから送信された証明書を印刷するテストプログラムを含めました。また、httpメッセージを出力します。プログラムは、getリクエストをgmail.comに送信します。証明書にCN=mail.google.comとしてCNが表示されます。誰かがこれをテストする気がありますか?iancurl -v -k https://gmail.com
がコメントで示唆しているように、まったく異なる結果を返すため、この動作は奇妙だと思います。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.cert.Certificate;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class SSLCheck {
public static String[] supportedCiphers = {"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV"};
public static void main(String[] args) {
int port = 443;
String host = "gmail.com";
try {
Socket sock = SSLSocketFactory.getDefault().createSocket(host, port);
sock.setSoTimeout(2000);
((SSLSocket)sock).setEnabledCipherSuites(supportedCiphers);
PrintWriter out = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
out.println("GET " + "/mail" + " HTTP/1.1");
out.println("Host: "+host);
out.println("Accept: */*");
out.println();
out.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
SSLSocket ssls = (SSLSocket)sock;
Certificate[] peercerts = ssls.getSession().getPeerCertificates();
System.out.println("***********************PEER CERTS**********************");
for(int i=0;i<peercerts.length;i++){
System.out.println(peercerts[i]);
System.out.println("*********************************************************");
}
String line;
while ((line = in.readLine())!=null) {
System.out.println(line);
}
out.close();
in.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
System.exit(0);
}
}
}