Т.о. проведен эксперимент с простейшей односторонней аутентификацией. Недостаток вышеприведенного кода очевиден. В нем применен TrustManager не проверяющий подлинность сервера. Такой код в некоторых случаях достаточен. Но в большинстве — нет. Следующим экспериментом используем нормальный TrustManager с проверкой серверного сертификата. Для этого надо создать truststore с серверным сертификатом. Ищу документацию и нахожу Generating a Keystore and Truststore. Из документа следует, что для создания truststore, нужно с помощью keytool импортировать в него сертификат. Для этого сертификат нужно сначала экспортировать. Делается это следующей командой:

keytool -export -keystore server.jks -alias server-test -storepass storepass -file server.cer

В итоге получается файл server.cer с сертификатом сервера. Теперь создаю на его основе truststore:

keytool -import -keystore clienttrust.jks -file server.cer -storepass storepass

В итоге получаю clienttrust.jks. Ниже на картинке дерево maven-овского проекта. Keystore и truststore лежат в директории resources.

ssl-test-source-tree.png

Добавляю в код клиента код читающий и задающий truststore для соединения. Ниже читается keystore с именем clienttrust.jks из ресурсов. Создается TrustManagerFactory на основе keystore.

char[] passphrase = "storepass".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(this.getClass().getResourceAsStream("clienttrust.jks"), passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);

Тестирую измененный клиент. Он работает. Серверный сертификат проходит проверку. Т.о. ниже клиентский код для односторонней аутентификации, осуществляющий проверку серверного сертификата по truststore:

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 testClientWithTrustStore()
        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");

        char[]  passphrase = "storepass".toCharArray();
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(this.getClass().getResourceAsStream("clienttrust.jks"), passphrase);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(ks);

        HostnameVerifier hostnameVerifier = new HostnameVerifier() {

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


        sslContext.init(null, tmf.getTrustManagers(), 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();
    }
}

Т.о. протестировано соединение с односторонней аутентификацией в двух вариантах: без аутентификации сервера и c аутентификацией сервера.

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