web-dev-qa-db-ja.com

クリアJava証明書キャッシュ(証明書の強制再読み込み)

ここで簡単な質問です。

有効期限が切れた証明書を使用してWebサイトにアクセスしようとすると、1つのアプリケーションでこの例外が発生しました:Java.security.cert.CertificateExpiredException

そこで、ウェブサイトのマシンから証明書を更新して再起動しました。 FirefoxまたはChrome=からアクセスしようとすると、新しい証明書がロードされます(有効期限は2040年近くに設定されています)。

問題は、Javaアプリケーションがこの証明書を更新していないようです。ある種の内部キャッシュでスタックしているようです。keystoreに追加して、 -Dcom.Sun.net.ssl.checkRevocation=falseのようなアプリケーションプロパティ。何をしても、常にJava.security.cert.CertificateExpiredExceptionがスローされます。

何か案は?

6

デフォルトのJavaキーストアの場所は、ホームディレクトリ(user.homeシステムプロパティ)の下の.keystoreファイルです。そのため、特に指定しない限り、Javaアプリケーション見えます。

実行してみてください:

$ keytool -list -keystore ~/.keystore -storepass changeit -v

期限切れの証明書がそこにあるかどうかを確認します。

使用する別のIDキーストアを指定する場合は、次のシステムプロパティを使用して指定できます。

javax.net.ssl.Keystore=/path/to/identity.jks
javax.net.ssl.keyStorePassword=mykeystorepassword

私は、FirefoxがNSSを使用しており、certutilユーティリティ(nss-toolsまたは類似のパッケージから)を使用してそのキーストアを表示できると信じています。

$ certutil -L -d sql:$HOME/.pki/nssdb

Pk12utilユーティリティを使用してキーと証明書をPKCS12ファイルに抽出できるはずですが、keytoolユーティリティを使用して新しい証明書署名リクエストを生成するだけの方が良いでしょう。

失効した証明書は、期限切れの証明書と同じではないため、checkRevocation = falseが機能しないことに注意してください。 CAは、証明書の有効期限が切れていなくても、いつでも証明書を取り消すことができます。これは、証明書が信頼されなくなったことを示しています。

1
Keith Burdis

この問題は、カスタムホスト名検証が使用されている場合にHttpsUrlConnectionがSNIを使用しない bug が原因であることが判明しました。

バグの回避策

javax.net.ssl.HttpsURLConnection connection = (javax.net.ssl.HttpsURLConnection) new Java.net.URL(url).openConnection();
connection.setHostnameVerifier(... hostname verifier which indirectly causes a bug ...);

//the remaining code fixes the bug by forcing the use of SNI even with the custom hostname verifier
final javax.net.ssl.SSLSocketFactory originalSocketFactory = connection.getSSLSocketFactory();
connection.setSSLSocketFactory(new javax.net.ssl.SSLSocketFactory() {
  public String[] getDefaultCipherSuites() {
    return originalSocketFactory.getDefaultCipherSuites();
  }

  public String[] getSupportedCipherSuites() {
    return originalSocketFactory.getSupportedCipherSuites();
  }

  private Java.net.Socket convertSocket(javax.net.ssl.SSLSocket socket, String Host) {
    javax.net.ssl.SNIHostName serverName = new javax.net.ssl.SNIHostName(Host);
    Java.util.List<javax.net.ssl.SNIServerName> serverNames = new Java.util.ArrayList<>(1);
    serverNames.add(serverName);
    javax.net.ssl.SSLParameters params = socket.getSSLParameters();
    params.setServerNames(serverNames);
    socket.setSSLParameters(params);
    return socket;
  }

  public Java.net.Socket createSocket(Java.net.Socket s, String Host, int port, boolean autoClose) throws IOException {

    //Host = new URL(url).getHost();
    javax.net.ssl.SSLSocket socket = (javax.net.ssl.SSLSocket) originalSocketFactory.createSocket(s,Host,port,autoClose);
    return convertSocket(socket, Host);
  }

  public Java.net.Socket createSocket(Java.net.InetAddress Host, int port) throws IOException {
    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(Host, port);
  }

  public Java.net.Socket createSocket(Java.net.InetAddress address, int port, Java.net.InetAddress localAddress, int localPort) throws IOException {
    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(address, port, localAddress, localPort);
  }

  public Java.net.Socket createSocket(String Host, int port) throws IOException {
    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(Host, port);
  }

  public Java.net.Socket createSocket(String Host, int port, Java.net.InetAddress localHost, int localPort) throws IOException {

    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(Host, port, localHost, localPort);
  }
});
1
user3338098

Java=新しくインポートされた証明書を認識するように強制する方法を探しているときに、この質問に出くわしました。

私にとって、証明書が(Windowsで)更新されなかったのは、すでにJavaインスタンスが実行されている(おそらく古い証明書キャッシュで))ためです。

私は単に古いJava=プロセスを強制終了し、次にそれが自動起動したときに(Gradle procが実行されているため)証明書が更新されました。

0
Coruscate5