Hi Xuelei, This isn't a significant issue in our case (there isn't any functional difference in what was being done in that specific catch block, in the code where this happened). I was only just curious if this was an intentional. The SSLProtocolException which is now being thrown, I think is a better one (having read its javadoc). I'll leave it at this now and won't create a bug.
Thank you for your inputs. -Jaikiran On 18/09/18 7:29 AM, Xuelei Fan wrote: > Hi Jaikiran, > > Normally, the thrown exception class can be an implementation choice, > and may be not reliable from version to version. We were trying to > use the same exception, but we may miss the use cases. I may suggest > to make the code independent from it. However, if the impact is > significant, please feel free file a bug and we will evaluate if there > is something we can do. > > Thanks, > Xuelei > > On 9/17/2018 6:30 PM, Jaikiran Pai wrote: >> Just checking back on this one. Is this an expected change? Personally, >> it's not a big issue in the code where this is happening for me. I'll >> probably just change the catch block to a more generic IOException. >> However, for any other code which relied on the previous SocketException >> catch block, they will now have to expect a different exception >> depending on what version of Java runtime it's running against. >> >> -Jaikiran >> >> >> On 12/09/18 9:11 PM, Jaikiran Pai wrote: >>> Please consider the code that's at the end of this mail. It is a simple >>> client/server code where a HTTPS server is created and set to >>> "needClientAuth". The client then uses HttpsURLConnection and (in this >>> case intentionally) doesn't present any certificate, expecting the >>> handshake to fail. In previous versions of Java, the handshake failure >>> in this code would throw a java.net.SocketException as below: >>> >>> Exception in thread "main" java.net.SocketException: Connection reset >>> at java.net.SocketInputStream.read(SocketInputStream.java:210) >>> at java.net.SocketInputStream.read(SocketInputStream.java:141) >>> at sun.security.ssl.InputRecord.readFully(InputRecord.java:465) >>> at sun.security.ssl.InputRecord.read(InputRecord.java:503) >>> at >>> sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983) >>> at >>> sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1779) >>> at >>> sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124) >>> at >>> sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1156) >>> at >>> sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1266) >>> >>> at >>> sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1178) >>> >>> at >>> sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348) >>> >>> at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052) >>> at sun.security.ssl.Handshaker.process_record(Handshaker.java:987) >>> at >>> sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072) >>> at >>> sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385) >>> >>> at >>> sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413) >>> at >>> sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397) >>> 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.getInputStream0(HttpURLConnection.java:1564) >>> >>> at >>> sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492) >>> >>> at >>> sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:263) >>> >>> at ClientCertTest.main(ClientCertTest.java:26) >>> >>> >>> However, in the Java 11 (release candidate) as well as Java 12 >>> (upstream), this code now throws a javax.net.ssl.SSLProtocolException >>> with the java.net.SocketException wrapped in it: >>> >>> Exception in thread "main" javax.net.ssl.SSLProtocolException: >>> Connection reset >>> at >>> java.base/sun.security.ssl.Alert.createSSLException(Alert.java:126) >>> at >>> java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321) >>> >>> at >>> java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264) >>> >>> at >>> java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259) >>> >>> at >>> java.base/sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1314) >>> >>> at >>> java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:839) >>> >>> at >>> java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:252) >>> >>> at >>> java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:292) >>> >>> at >>> java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:351) >>> >>> at >>> java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:746) >>> >>> at >>> java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:689) >>> at >>> java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:717) >>> at >>> java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1604) >>> >>> at >>> java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509) >>> >>> at >>> java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:245) >>> >>> at ClientCertTest.main(ClientCertTest.java:26) >>> Caused by: java.net.SocketException: Connection reset >>> at >>> java.base/java.net.SocketInputStream.read(SocketInputStream.java:186) >>> at >>> java.base/java.net.SocketInputStream.read(SocketInputStream.java:140) >>> at >>> java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:448) >>> >>> at >>> java.base/sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:68) >>> >>> at >>> java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1104) >>> >>> at >>> java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:823) >>> >>> ... 10 more >>> >>> >>> Is this an intentional and expected change? As far as I could see, >>> there >>> isn't any specific API which says SocketException will be thrown in >>> this >>> case, so maybe the client applications which were catching this >>> specific >>> exception are expected to change their catch block to something more >>> generic like a IOException? >>> >>> Here's the code to reproduce this: >>> >>> import java.io.*; >>> import java.net.*; >>> import javax.net.ssl.*; >>> import java.util.*; >>> import java.security.*; >>> import com.sun.net.httpserver.*; >>> import java.security.cert.*; >>> >>> >>> public class ClientCertTest { >>> private static final String keyFilename = "keystore"; >>> private static final String keystorePass = "passphrase"; >>> >>> public static void main(final String[] args) throws Exception { >>> final int port = 12345; >>> final HttpsServer server = startServer("localhost", port); >>> try { >>> final URL targetURL = new URL("https://localhost:" + >>> port + >>> "/"); >>> final SSLContext sslctx = SSLContext.getInstance("TLS"); >>> sslctx.init(null, new TrustManager[] {new TrustAll()}, >>> null); >>> HttpsURLConnection.setDefaultHostnameVerifier((h, s) -> >>> {return true;}); >>> final HttpsURLConnection conn = (HttpsURLConnection) >>> targetURL.openConnection(); >>> // setup the HTTPS connection to use our SocketFactory >>> which >>> doesn't present >>> // any cert when asked for (and thus is expected to fail >>> handshake) >>> conn.setSSLSocketFactory(sslctx.getSocketFactory()); >>> try (final InputStream is = conn.getInputStream()) { >>> is.read(); >>> } catch (SocketException se) { >>> System.out.println("*** Received the expected >>> SocketException: " + se.getMessage()); >>> throw se; >>> } >>> } finally { >>> server.stop(0); >>> System.out.println("Stopped server"); >>> } >>> } >>> >>> private static HttpsServer startServer(final String host, final >>> int >>> port) throws Exception { >>> final HttpsServer server = HttpsServer.create(new >>> InetSocketAddress(host, port), 0); >>> final Thread t = new Thread(() -> { >>> try { >>> final SSLContext sslctx = >>> SSLContext.getInstance("TLS"); >>> final KeyManagerFactory kmf = >>> KeyManagerFactory.getInstance("SunX509"); >>> final KeyStore ks = KeyStore.getInstance("JKS"); >>> try (final FileInputStream fis = new >>> FileInputStream(keyFilename)) { >>> ks.load(fis, keystorePass.toCharArray()); >>> } >>> kmf.init(ks, keystorePass.toCharArray()); >>> sslctx.init(kmf.getKeyManagers(), null, null); >>> final SSLParameters sslParameters = >>> sslctx.getDefaultSSLParameters(); >>> // need client auth >>> sslParameters.setNeedClientAuth(true); >>> server.setHttpsConfigurator(new >>> HttpsConfigurator(sslctx) { >>> @Override >>> public void configure(final HttpsParameters >>> params) { >>> params.setSSLParameters(sslParameters); >>> } >>> }); >>> server.start(); >>> System.out.println("Started server at " + >>> server.getAddress()); >>> } catch(Exception e) { >>> throw new RuntimeException(e); >>> } >>> }); >>> t.start(); >>> return server; >>> } >>> >>> private static class TrustAll implements X509TrustManager { >>> >>> @Override >>> public void checkClientTrusted(X509Certificate[] chain, String >>> authType) throws CertificateException { >>> return; >>> } >>> >>> @Override >>> public void checkServerTrusted(X509Certificate[] chain, String >>> authType) throws CertificateException { >>> return; >>> } >>> >>> @Override >>> public X509Certificate[] getAcceptedIssuers() { >>> return new X509Certificate[0]; >>> } >>> } >>> } >>> >>> >>> P.S: The "keystore" file in this example is the same one that's present >>> in the openjdk repo at test/jdk/javax/net/ssl/etc/keystore, so in order >>> to run the above code, that file can just be placed in the current >>> working dir. >>> >>> -Jaikiran >>> >>