Пример простого HTTPS соединения без проверки сертификата сервера

Далее коннекчусь к своему серверу программно. Для начала делаю такой код:

@Test
public void testSimpleHttpsClient()
    throws CertificateException, InterruptedException, UnrecoverableKeyException, NoSuchAlgorithmException,
           IOException, KeyManagementException, KeyStoreException {

    startServer(8080);

    URL url = new URL("https://localhost:8080/");

    HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
    con.setRequestMethod( "GET" );

    SSLContext sslContext = SSLContext.getInstance("TLS");

    sslContext.init(null, null, null);
    con.setSSLSocketFactory(sslContext.getSocketFactory());

    int responseCode = con.getResponseCode();
    InputStream inputStream;
    if (responseCode == HttpURLConnection.HTTP_OK) {
        inputStream = con.getInputStream();
    } else {
        inputStream = con.getErrorStream();
    }

    // Process the response
    BufferedReader reader;
    String line = null;
    reader = new BufferedReader( new InputStreamReader( inputStream ) );
    while( ( line = reader.readLine() ) != null )
    {
        System.out.println( line );
    }

    inputStream.close();
}

Стартую сервер на 8080 порту, в метод startServer(int port) перенесен весь код, из предыдущего теста.

startServer(8080);

Указываю, что нужно создать HttpsUrlConnection на URL https://localhost:8080 методом GET.

URL url = new URL("https://localhost:8080/");
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setRequestMethod( "GET" );

Создаю «пустой» SSLContext и на его основе создаю SSLSocketFactory, который передаю в параметры соединению.

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
con.setSSLSocketFactory(sslContext.getSocketFactory());

Запускаю на тестирование, получаю исключение:

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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1764)
....

Ошибка говорит о том, что не найден сертификат, подтверждающий подлинность сервера. Правильно, я не указал TrustManager-ов. Соответственно сертификаты проверить нельзя. Добавляю пустой TrustManager, пока без сертификатов, разрешающий любые сертификаты.

TrustManager[] trustManagers = new TrustManager[] {
    new X509TrustManager() {

        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

        public void checkServerTrusted(X509Certificate[] certs, String authType) {  }

    }
};

Тестируюсь. Теперь «валидация» сертификата проходит, но получаю другое исключение:

java.io.IOException: HTTPS hostname wrong: should be
at sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(HttpsClient.java:524)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:448)

Теперь сертификат сервера проверяется, но не проходит проверку имя хоста. Добавляю свой собственный HostnameVerifier:

HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return s.equals(sslSession.getPeerHost());
}
};
con.setHostnameVerifier(hostnameVerifier);

Тестируюсь, соединение успешно. Результирующий код клиента и сервера, пока, такой:

import com.sun.net.httpserver.*;
import org.junit.Test;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SimpleServerTest {

    static class MyHandler implements HttpHandler {
        public void handle(HttpExchange t) throws IOException {

          String response = "This is the response";
          t.sendResponseHeaders(200, response.length());
          OutputStream os = t.getResponseBody();
          os.write(response.getBytes());

        }
    }

    void startServer(int port) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException,
    UnrecoverableKeyException, InterruptedException, KeyManagementException{
		HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 5);
		server.createContext("/", new MyHandler());

		char[] storepass = "storepass".toCharArray();
		char[] keypass = "serverpass".toCharArray();

		KeyStore ks = KeyStore.getInstance("JKS");
		ks.load(SimpleServerTest.class.getResourceAsStream("server.jks"), storepass);

		KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
		kmf.init(ks, keypass);

		SSLContext sslContext = SSLContext.getInstance("TLS");
		sslContext.init(kmf.getKeyManagers(), new TrustManager[]{}, null);

		server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {

			public void configure (HttpsParameters params) {

			// get the remote address if needed
			InetSocketAddress remote = params.getClientAddress();

			SSLContext c = getSSLContext();

			// get the default parameters
			SSLParameters sslparams = c.getDefaultSSLParameters();

			params.setSSLParameters(sslparams);
			// statement above could throw IAE if any params invalid.
			// eg. if app has a UI and parameters supplied by a user.

			}

		});

    	server.setExecutor(null); // creates a default executor
    	server.start();
	}


    @Test
    public void testSimpleHttpsClientWithTrustManagerAndVerifier()
        throws CertificateException, InterruptedException, UnrecoverableKeyException, NoSuchAlgorithmException,
               IOException, KeyManagementException, KeyStoreException {

        startServer(8080);

        URL url = new URL("https://localhost:8080/");

        HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
        con.setRequestMethod( "GET" );

        SSLContext sslContext = SSLContext.getInstance("TLS");

        TrustManager[] trustManagers = new TrustManager[] {
            new X509TrustManager() {

                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {  }

            }
        };
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {

            public boolean verify(String s, SSLSession sslSession) {
                return s.equals(sslSession.getPeerHost());
            }
        };
        con.setHostnameVerifier(hostnameVerifier);


        sslContext.init(null, trustManagers, null);
        con.setSSLSocketFactory(sslContext.getSocketFactory());


        int responseCode = con.getResponseCode();
        InputStream inputStream;
        if (responseCode == HttpURLConnection.HTTP_OK) {
            inputStream = con.getInputStream();
        } else {
            inputStream = con.getErrorStream();
        }

        // Process the response
        BufferedReader reader;
        String line = null;
        reader = new BufferedReader( new InputStreamReader( inputStream ) );
        while( ( line = reader.readLine() ) != null )
        {
            System.out.println( line );
        }

        inputStream.close();
    }
}

Взято:
https://dev64.wordpress.com/2013/06/18/configure-embedded-jdk-http-server-for-https/