web-dev-qa-db-ja.com

javaでssl証明書チェックをバイパスする方法

アクセスしたいSOAPリモートVMでhttpsがホストされているWebサービスURL。HttpURLConnectionを使用してアクセスしているときに例外が発生します。

これが私のコードです:

import javax.net.ssl.*;
import Java.io.OutputStream;
import Java.net.HttpURLConnection;
import Java.net.URL;
import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;

/**
 * Created by prasantabiswas on 07/03/17.
 */
public class Main
{
    public static void main(String [] args)
    {
        try
        {
            URL url = new URL("https://myhost:8913/myservice/service?wsdl");
            HttpURLConnection http = null;

            if (url.getProtocol().toLowerCase().equals("https")) {
                trustAllHosts();
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setHostnameVerifier(DO_NOT_VERIFY);
                http = https;
            } else {
                http = (HttpURLConnection) url.openConnection();
            }
            String SOAPAction="";
//            http.setRequestProperty("Content-Length", String.valueOf(b.length));
            http.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
            http.setRequestProperty("SOAPAction", SOAPAction);
            http.setRequestMethod("GET");
            http.setDoOutput(true);
            http.setDoInput(true);
            OutputStream out = http.getOutputStream();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    private static void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new Java.security.cert.X509Certificate[] {};
            }

            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException
            {
            }

            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }
        } };

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new Java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

次の例外が発生します。

javax.net.ssl.SSLHandshakeException: Java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
    at Sun.security.ssl.Alerts.getSSLException(Alerts.Java:192)
    at Sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.Java:1949)
    at Sun.security.ssl.Handshaker.fatalSE(Handshaker.Java:302)
    at Sun.security.ssl.Handshaker.fatalSE(Handshaker.Java:296)
    at Sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.Java:1509)
    at Sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.Java:216)
    at Sun.security.ssl.Handshaker.processLoop(Handshaker.Java:979)
    at Sun.security.ssl.Handshaker.process_record(Handshaker.Java:914)
    at Sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.Java:1062)
    at Sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.Java:1375)
    at Sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1403)
    at Sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1387)
    at Sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.Java:559)
    at Sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.Java:185)
    at Sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.Java:1283)
    at Sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.Java:1258)
    at Sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.Java:250)
    at Main.main(Main.Java:35)
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.lang.reflect.Method.invoke(Method.Java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.Java:147)
Caused by: Java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
    at Sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.Java:1055)
    at Sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.Java:981)
    at Sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.Java:923)
    at Sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.Java:1491)
    ... 18 more

グーグル検索とは異なるソリューションを試してみましたが、それらのどれも機能しませんでした。別のvmでテストを実行するため、keytoolの使用を避けたいです。

誰かがこれに対する解決策を持っていますか?

11
Prasanta Biswas

HttpsURLConnection.setDefaultSSLSocketFactoryと独自のTrustManagerまたはX509ExtendedTrustManagerの実装を使用する代わりに、TrustManagerFactoryKeyStoreとともに使用し、証明書を発行した証明書を使用できます。信頼する必要があり(自己署名証明書の場合、これはホスト証明書と同じです)、特定のインスタンスでHttpsURLConnection.setSSLSocketFactoryを呼び出す必要があります。これはコードが少なく、すべてのHTTPS証明書を信頼することによるセキュリティの問題を回避します。

main内:

            if (url.getProtocol().toLowerCase().equals("https")) {
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setSSLSocketFactory(createSSLSocketFactory());
                http = https;
            }

メソッドcreateSSLSocketFactoryは次のようになります。

    private static SSLSocketFactory createSSLSocketFactory() {
         File crtFile = new File("server.crt");
         Certificate certificate =          CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));

         KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
         keyStore.load(null, null);
         keyStore.setCertificateEntry("server", certificate);

         TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
         trustManagerFactory.init(keyStore);

         SSLContext sslContext = SSLContext.getInstance("TLS");
         sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

         return sslContext.getSocketFactory();
    }
1