I have a custom HostnameVerifier that attempts to examine the certificate chain 
using SSLSession#getPeerCertificates(). After upgrading to Java 11, where it 
seems that TLSv1.3 is used by default, I am seeing that getPeerCertificates() 
throws an SSLPeerUnverifiedException after an HTTP redirect has occurred. If I 
force the protocol to TLSv1.2 this does not occur. If there is no redirect, 
then this does not occur.

Is this a bug in Java or a change in behavior with TLSv1.3?

The code below demonstrates the problem when 'protocol' is either 'TLS' or 
'TLSv1.3' and path is '/redirect'.

doTest("TLSv1.3", "/redirect"); // Fails with SSLPeerUnverifiedException
doTest("TLSv1.3", "/content"); // Succeeds
doTest("TLSv1.2", "/redirect"); // Succeeds
doTest("TLSv1.2", "/content"); // Succeeds

    private void doTest(String protocol, String path) throws IOException, 
NoSuchAlgorithmException, KeyManagementException
    {
            whenHttp(server)
                            .match(get("/redirect"))
                            .then(status(HttpStatus.MOVED_PERMANENTLY_301), 
contentType("text/html"), header("Location", "/content"), 
stringContent("redirected"));
            whenHttp(server)
                            .match(get("/content"))
                            .then(ok(), contentType("text/html"), 
stringContent("ok"));

            URL url = new URL("https", "localhost", server.getPort(), path);
            HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
            SSLContext ctx = SSLContext.getInstance(protocol);
            TrustManager[] tms = {new X509TrustManager()
            {
                    @Override public void checkClientTrusted(X509Certificate[] 
chain, String authType){}
                    @Override public void checkServerTrusted(X509Certificate[] 
chain, String authType){}
                    @Override public X509Certificate[] getAcceptedIssuers() { 
return new X509Certificate[0]; }
            }};
            ctx.init(null, tms, new SecureRandom());
            conn.setSSLSocketFactory(ctx.getSocketFactory());
            conn.setHostnameVerifier(new HostnameVerifier()
            {
                    @Override
                    public boolean verify(String hostname, SSLSession session)
                    {
                            java.security.cert.Certificate[] chain = null;
                            try
                            {
                                    chain = session.getPeerCertificates();
                            }
                            catch (SSLPeerUnverifiedException e)
                            {
                                    throw new RuntimeException(e);
                            }
                            return true;
                    }
            });
            int status = conn.getResponseCode();
            assertEquals(200, status);
    }


Thanks,
Dan

Daniel L. Christensen
Distinguished Engineer
Micro Focus
http://www.microfocus.com


<<attachment: Daniel_Christensen.vcf>>

Reply via email to