web-dev-qa-db-ja.com

Javaキーストアにインポートされた証明書、JVMは新しい証明書を無視します

SSL経由でLDAPサーバーに接続するために、Tomcat 6上でアプリケーションを実行しようとしています。

サーバーの証明書をキーストアにインポートしました:

C:\Program Files\Java\jdk1.6.0_32\jre\lib\security>keytool -importcert -trustcacerts -file mycert -alias ca_alias -keystore "c:\Program Files\Java\jdk1.6.0_32\jre\lib\security\cacerts"

SSLデバッグをオンにしてTomcatを起動すると、ログによると、Tomcatは正しい証明書ファイルを使用しています。

trustStore is: C:\Program Files\Java\jdk1.6.0_32\jre\lib\security\cacerts

ただし、Tomcatは、インポートしたばかりの証明書を追加しません-cacertsファイル内の他のすべての証明書はログに出力され、接続は失敗します。

handling exception: 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

Tomcatを再起動しても効果はありません。 keytool -listコマンドを使用して、新しい証明書が実際にファイルに存在することを確認しました。

Tomcatが私の新しい証明書を無視し続けるのはなぜですか?

編集:

問題はWindows 7 VirtualStoreが原因で発生したようです。 Keytoolはcacertファイルの新しいコピーを作成し、Tomcatは元のファイルを使用しました。

19
tputkonen

証明書をキーストアにインポートした後、JVMを再起動する必要があります。

16
SSLKida

CN情報は同じだがエイリアスが異なるキーがあるかどうかを確認します。

以前に新しいバージョンの証明書をインポートしようとしたが、古いバージョンをキーストアに残したときに、同様の問題が発生しました。私のJavaプログラムは、キーストアで最初に一致するCNキー(古い期限切れのもの)を見つけ、それを使用しようとしましたが、CNにも一致する新しいキーがあったとしても、.

また、認証ルート証明書(および該当する場合は中間証明書)がキーストアに存在することを確認します。 VerisignやGlobalsignなどの主要なセキュリティプロバイダーのいずれかに対して認証を行う場合、通常はルート証明書と中間証明書が提供されます。これらの証明書がキ​​ーストアにすでに存在する場合は、それらがまだ有効であることを確認してください。資格情報を検証する方法を理解できるように、認証チェーンからルートまでのすべての個人証明書からキーストアに存在するすべての証明書が必要です。

5
wattostudios

あなたが説明したのは、cmd.exeとWindows Serverの管理グループのメンバーである通常のユーザーを使用しているときに正確に得たものです。変更をcacertsファイルに適用するには、管理モードでcmd.exeを開始する必要があります。少なくともWin2k8 OSでは。

これを行わないと、キャレットはkeytool.exe -listビューに新しく追加された証明書を表示しますが、Tomcatには表示されません。なぜだかわかりません。しかし、管理者として開始したcmd.exeで追加した場合、Tomcatは新しく追加された証明書で問題ありません。

Djavax.net.debug="ssl,handshake"を使用して、Tomcatがcacertsファイルから読み取る内容を確認することもできます。

2
jturunen

私の場合、何が問題かを理解する前に多くのことを調べました...証明書を別のキーストアに追加し、チェーン内のすべての証明書を追加しました(無意味です)、自分の正気のために証明書を再度ダウンロードしましたシリアル番号をチェックし、ダウンロードした証明書を調べて、すべての情報が正しいことを確認しました。

問題をデバッグするために、TLS検証クライアントアプリを作成してしまいました。接続しているリモートサーバーがTLS 1.2のみをサポートしている(私のバージョンのJava 7)ではデフォルトで無効になっている)だけでなく、サーバーはクライアントで有効になっている暗号もサポートしていませんでした。 Java 7では、サポートされている暗号の半分未満が有効になっており、その多くは本当に安全ではなく、最も安全な暗号の一部は無効になっています。

いくつかのクロスチェックを行った後、TLS 1.2でサポートされている安全な暗号の次の順序付きリストを思いつきました。

new String[] {
    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384",
    "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256",
    "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
    "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
    "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",
    "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",
    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
    "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
    "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
    "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
    "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
    "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
    "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
    "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256",
    "TLS_DHE_RSA_WITH_AES_256_CCM",
    "TLS_DHE_RSA_WITH_AES_128_CCM",
    "TLS_DHE_PSK_WITH_AES_256_CCM",
    "TLS_DHE_PSK_WITH_AES_128_CCM",
    "TLS_CHACHA20_POLY1305_SHA256",
    "TLS_AES_256_GCM_SHA384",
    "TLS_AES_128_GCM_SHA256",
    "TLS_AES_128_CCM_SHA256"
}

暗号の専門家がいる場合は、このリストを自由に更新してください。私は Qualys SSL LabsこのInformation Security SEの回答 、および [〜#〜] iana [〜#〜] をソースとして使用しました。

私が使用したソースコードのサンプルが必要な方は、以下を参照してください。私はApache Commons HttpClient 3.0を使用していたため、おそらく以下のバイナリをダウンロードする必要があります。

TLS12SocketFactory.Java

import Java.io.*;
import Java.net.*;
import Java.util.*;
import org.Apache.commons.httpclient.params.HttpConnectionParams;
import org.Apache.commons.httpclient.protocol.*;
import org.Apache.commons.lang.StringUtils;

public class TLS12SocketFactory implements SecureProtocolSocketFactory {

        private final SecureProtocolSocketFactory base;
        public TLS12SocketFactory()
        {
            this.base = (SecureProtocolSocketFactory)Protocol.getProtocol("https").getSocketFactory();
        }
        private Socket acceptOnlyTLS12(Socket socket)
        {
            if(socket instanceof javax.net.ssl.SSLSocket) {
                final javax.net.ssl.SSLSocket s = (javax.net.ssl.SSLSocket)socket;

                // Set TLS 1.2
                s.setEnabledProtocols(new String[]{ "TLSv1.2" });

                // Using recommended ciphers from https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#table-tls-parameters-4
                List<String> recommended = new ArrayList(Arrays.asList(new String[]{ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_CCM", "TLS_DHE_RSA_WITH_AES_128_CCM", "TLS_DHE_PSK_WITH_AES_256_CCM", "TLS_DHE_PSK_WITH_AES_128_CCM", "TLS_CHACHA20_POLY1305_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_AES_128_CCM_SHA256" }));
                recommended.retainAll(Arrays.asList(s.getSupportedCipherSuites()));
                if(recommended.size() == 0) {
                    System.err.println("No supported modern ciphers. Update crypto policy or install JCE Unlimited Strength Jurisdiction Policy files." + System.lineSeparator());
                } else if(recommended.size() < 3) {
                    System.out.println("Few supported modern ciphers. It's recommended to update crypto policy or install JCE Unlimited Strength Jurisdiction Policy files." + System.lineSeparator());
                }
                s.setEnabledCipherSuites(recommended.toArray(new String[0]));

                // Log matched cipher and cert
                s.addHandshakeCompletedListener(new javax.net.ssl.HandshakeCompletedListener() {
                    @Override
                    public void handshakeCompleted(javax.net.ssl.HandshakeCompletedEvent hce) {
                        String print = s.getInetAddress().getHostName() + System.lineSeparator() + hce.getCipherSuite() + System.lineSeparator();
                        try {
                            for(Java.security.cert.Certificate cert : hce.getPeerCertificates()) {
                                List<String> certStrings = Arrays.asList(cert.toString().split("\r?\n"));
                                for(int line = 0; line < certStrings.size(); line++) {
                                    if(certStrings.get(line).startsWith("Certificate Extensions:")) {
                                        print += System.lineSeparator() + StringUtils.join(certStrings.subList(2, line-1), System.lineSeparator()) + System.lineSeparator();
                                        break;
                                    }
                                }
                            }
                        } catch (javax.net.ssl.SSLPeerUnverifiedException ex) {
                            print += "Non-certificate based cipher used" + System.lineSeparator();
                        }
                        System.out.println(print);
                    }
                });
            }
            return socket;
        }

        @Override
        public Socket createSocket(String Host, int port) throws IOException
        {
            return acceptOnlyTLS12(base.createSocket(Host, port));
        }
        @Override
        public Socket createSocket(String Host, int port, InetAddress localAddress, int localPort) throws IOException
        {
            return acceptOnlyTLS12(base.createSocket(Host, port, localAddress, localPort));
        }
        @Override
        public Socket createSocket(String Host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException
        {
            return acceptOnlyTLS12(base.createSocket(Host, port, localAddress, localPort, params));
        }
        @Override
        public Socket createSocket(Socket socket, String Host, int port, boolean autoClose) throws IOException
        {
            return acceptOnlyTLS12(base.createSocket(socket, Host, port, autoClose));
        }
}

Main.Java

import Java.io.*;
import Java.security.*;
import Java.security.cert.*;
import Java.util.*;
import org.Apache.commons.httpclient.protocol.Protocol;
import org.Apache.commons.httpclient.*;
import org.Apache.commons.httpclient.cookie.CookiePolicy;
import org.Apache.commons.httpclient.methods.*;
import org.Apache.commons.httpclient.params.HttpClientParams;

public class Main {
    public static void main(String[] args) {
        List<Java.net.URI> locations = new ArrayList<>();
        for(String arg : args) {
            Java.net.URI location = Java.net.URI.create(arg);
            if(location.isAbsolute() && location.getScheme().equals("https")) {
                locations.add(location);
            } else {
                System.out.println("Skipping invalid URL: " + arg);
            }
        }
        System.out.println("Connecting to URL's");
        System.out.println();
        System.out.println("-------------------------");

        TLS12SocketFactory tls12factory = new TLS12SocketFactory();
        Protocol.registerProtocol("httpss", new Protocol("httpss", tls12factory, 443));
        for(Java.net.URI location : locations) {
            System.out.println();
            try {
                // Form request
                String tls12url = location.toString().replaceFirst("^https:", "httpss:");
                HttpMethod method = new HeadMethod(tls12url);

                // Send request
                HttpClientParams params = new HttpClientParams();
                params.setParameter(HttpClientParams.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
                new HttpClient(params).executeMethod(method);
                method.setFollowRedirects(true);

                // Print response
                System.out.println(location.toString());
                System.out.println(method.getStatusLine().toString());
            } catch (javax.net.ssl.SSLHandshakeException ex) {
                System.out.println("There was an error making a secure connection to " + location.getHost());
                ex.printStackTrace(System.out);
            } catch (HttpException ex) {
                System.out.println("There was an error with the external webpage");
                ex.printStackTrace(System.out);
            } catch (Exception ex) {
                System.out.println("Could not complete request");
                ex.printStackTrace(System.out);
            }
        }
        System.out.println();
        System.out.println("-------------------------");
        System.out.println();
        try {
            // Load supported SSL Ciphers
            System.out.println("Supported ciphers");
            System.out.println();
            System.out.println("-------------------------");
            System.out.println();
            javax.net.ssl.SSLSocket socket = (javax.net.ssl.SSLSocket)tls12factory.createSocket("www.google.com", 443);
            for(String cipher : socket.getSupportedCipherSuites()) {
                System.out.println(cipher);
            }
            System.out.println();
            System.out.println("-------------------------");
            System.out.println();

            // Load enabled SSL Ciphers
            System.out.println("Enabled ciphers");
            System.out.println();
            System.out.println("-------------------------");
            System.out.println();
            for(String cipher : socket.getEnabledCipherSuites()) {
                System.out.println(cipher);
            }
            System.out.println();
            System.out.println("-------------------------");
            System.out.println();

            // Load the JDK's cacerts keystore file
            String filename = System.getProperty("Java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
            System.out.println("Loading keystore");
            System.out.println(filename);
            System.out.println();
            System.out.println("-------------------------");
            System.out.println();
            FileInputStream is = new FileInputStream(filename);
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            String password = "changeit";
            keystore.load(is, password.toCharArray());

            // This class retrieves the most-trusted CAs from the keystore
            PKIXParameters params = new PKIXParameters(keystore);

            // Get the set of trust anchors, which contain the most-trusted CA certificates
            for (TrustAnchor ta : params.getTrustAnchors()) {
                // Print certificate
                System.out.println(ta.getTrustedCert());
            }
        } catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | IOException ex) {
            System.out.println("Could not load keystore");
            ex.printStackTrace(System.out);
        }
    }
}
0
Pluto