From 5aa15d557811bbdf0f23b150f361bb42fb7591cb Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Tue, 26 Feb 2019 23:08:43 +0000 Subject: [PATCH] Fix for Bug#93590 (29054329), javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify. --- CHANGES | 2 + .../mysql/cj/protocol/NetworkResources.java | 58 ++++++++++--------- .../mysql/cj/protocol/ExportControlled.java | 18 +++--- .../mysql/cj/protocol/a/NativeProtocol.java | 19 +++--- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/CHANGES b/CHANGES index e851fea3c..03750e10b 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,8 @@ Version 8.0.16 + - Fix for Bug#93590 (29054329), javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify. + - Fix for Bug#94414 (29384853), Connector/J RPM package have version number in path. - Fix for Bug#27786499, REDUNDANT FILES IN DEBIAN PACKAGE FOR DEBIAN9(COMMUNITY PACKAGE) FOR CJAVA. diff --git a/src/main/core-api/java/com/mysql/cj/protocol/NetworkResources.java b/src/main/core-api/java/com/mysql/cj/protocol/NetworkResources.java index 85e551e16..7a7aef02c 100644 --- a/src/main/core-api/java/com/mysql/cj/protocol/NetworkResources.java +++ b/src/main/core-api/java/com/mysql/cj/protocol/NetworkResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 2.0, as published by the @@ -50,47 +50,51 @@ public NetworkResources(Socket mysqlConnection, InputStream mysqlInput, OutputSt */ public final void forceClose() { try { - try { - if (this.mysqlInput != null) { - this.mysqlInput.close(); - } - } finally { - if (this.mysqlConnection != null && !this.mysqlConnection.isClosed() && !this.mysqlConnection.isInputShutdown()) { - try { - this.mysqlConnection.shutdownInput(); - } catch (UnsupportedOperationException ex) { - // ignore, some sockets do not support this method + if (!ExportControlled.isSSLEstablished(this.mysqlConnection)) { // Fix for Bug#56979 does not apply to secure sockets. + try { + if (this.mysqlInput != null) { + this.mysqlInput.close(); + } + } finally { + if (this.mysqlConnection != null && !this.mysqlConnection.isClosed() && !this.mysqlConnection.isInputShutdown()) { + try { + this.mysqlConnection.shutdownInput(); + } catch (UnsupportedOperationException e) { + // Ignore, some sockets do not support this method. + } } } } - } catch (IOException ioEx) { - // we can't do anything constructive about this + } catch (IOException e) { + // Can't do anything constructive about this. } try { - try { - if (this.mysqlOutput != null) { - this.mysqlOutput.close(); - } - } finally { - if (this.mysqlConnection != null && !this.mysqlConnection.isClosed() && !this.mysqlConnection.isOutputShutdown()) { - try { - this.mysqlConnection.shutdownOutput(); - } catch (UnsupportedOperationException ex) { - // ignore, some sockets do not support this method + if (!ExportControlled.isSSLEstablished(this.mysqlConnection)) { // Fix for Bug#56979 does not apply to secure sockets. + try { + if (this.mysqlOutput != null) { + this.mysqlOutput.close(); + } + } finally { + if (this.mysqlConnection != null && !this.mysqlConnection.isClosed() && !this.mysqlConnection.isOutputShutdown()) { + try { + this.mysqlConnection.shutdownOutput(); + } catch (UnsupportedOperationException e) { + // Ignore, some sockets do not support this method. + } } } } - } catch (IOException ioEx) { - // we can't do anything constructive about this + } catch (IOException e) { + // Can't do anything constructive about this. } try { if (this.mysqlConnection != null) { this.mysqlConnection.close(); } - } catch (IOException ioEx) { - // we can't do anything constructive about this + } catch (IOException e) { + // Can't do anything constructive about this. } } } diff --git a/src/main/core-impl/java/com/mysql/cj/protocol/ExportControlled.java b/src/main/core-impl/java/com/mysql/cj/protocol/ExportControlled.java index b03600e64..b8b781e63 100644 --- a/src/main/core-impl/java/com/mysql/cj/protocol/ExportControlled.java +++ b/src/main/core-impl/java/com/mysql/cj/protocol/ExportControlled.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 2.0, as published by the @@ -289,11 +289,12 @@ public static Socket performTlsHandshake(Socket rawSocket, SocketConnection sock PropertySet pset = socketConnection.getPropertySet(); - SslMode sslMode = pset. getEnumProperty(PropertyKey.sslMode).getValue(); + SslMode sslMode = pset.getEnumProperty(PropertyKey.sslMode).getValue(); boolean verifyServerCert = sslMode == SslMode.VERIFY_CA || sslMode == SslMode.VERIFY_IDENTITY; - KeyStoreConf trustStore = !verifyServerCert ? new KeyStoreConf() : getTrustStoreConf(pset, PropertyKey.trustCertificateKeyStoreUrl, - PropertyKey.trustCertificateKeyStorePassword, PropertyKey.trustCertificateKeyStoreType, verifyServerCert && serverVersion == null); + KeyStoreConf trustStore = !verifyServerCert ? new KeyStoreConf() + : getTrustStoreConf(pset, PropertyKey.trustCertificateKeyStoreUrl, PropertyKey.trustCertificateKeyStorePassword, + PropertyKey.trustCertificateKeyStoreType, verifyServerCert && serverVersion == null); KeyStoreConf keyStore = getKeyStoreConf(pset, PropertyKey.clientCertificateKeyStoreUrl, PropertyKey.clientCertificateKeyStorePassword, PropertyKey.clientCertificateKeyStoreType); @@ -573,7 +574,7 @@ public static SSLContext getSSLContext(String clientCertificateKeyStoreUrl, Stri } public static boolean isSSLEstablished(Socket socket) { - return SSLSocket.class.isAssignableFrom(socket.getClass()); + return socket == null ? false : SSLSocket.class.isAssignableFrom(socket.getClass()); } public static RSAPublicKey decodeRSAPublicKey(String key) throws RSAException { @@ -616,11 +617,12 @@ public static AsynchronousSocketChannel startTlsOnAsynchronousChannel(Asynchrono PropertySet propertySet = socketConnection.getPropertySet(); - SslMode sslMode = propertySet. getEnumProperty(PropertyKey.sslMode).getValue(); + SslMode sslMode = propertySet.getEnumProperty(PropertyKey.sslMode).getValue(); boolean verifyServerCert = sslMode == SslMode.VERIFY_CA || sslMode == SslMode.VERIFY_IDENTITY; - KeyStoreConf trustStore = !verifyServerCert ? new KeyStoreConf() : getTrustStoreConf(propertySet, PropertyKey.trustCertificateKeyStoreUrl, - PropertyKey.trustCertificateKeyStorePassword, PropertyKey.trustCertificateKeyStoreType, true); + KeyStoreConf trustStore = !verifyServerCert ? new KeyStoreConf() + : getTrustStoreConf(propertySet, PropertyKey.trustCertificateKeyStoreUrl, PropertyKey.trustCertificateKeyStorePassword, + PropertyKey.trustCertificateKeyStoreType, true); KeyStoreConf keyStore = getKeyStoreConf(propertySet, PropertyKey.clientCertificateKeyStoreUrl, PropertyKey.clientCertificateKeyStorePassword, PropertyKey.clientCertificateKeyStoreType); diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java index 5fd92c018..939815936 100644 --- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java +++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java @@ -1311,18 +1311,19 @@ public final void skipPacket() { */ public final void quit() { try { - // we're not going to read the response, fixes BUG#56979 Improper connection closing logic leads to TIME_WAIT sockets on server - try { - if (!this.socketConnection.getMysqlSocket().isClosed()) { - try { - this.socketConnection.getMysqlSocket().shutdownInput(); - } catch (UnsupportedOperationException ex) { - // ignore, some sockets do not support this method + if (!ExportControlled.isSSLEstablished(this.socketConnection.getMysqlSocket())) { // Fix for Bug#56979 does not apply to secure sockets. + if (!this.socketConnection.getMysqlSocket().isClosed()) { + try { + // The response won't be read, this fixes BUG#56979 [Improper connection closing logic leads to TIME_WAIT sockets on server]. + this.socketConnection.getMysqlSocket().shutdownInput(); + } catch (UnsupportedOperationException e) { + // Ignore, some sockets do not support this method. + } } } - } catch (IOException ioEx) { - this.log.logWarn("Caught while disconnecting...", ioEx); + } catch (IOException e) { + // Can't do anything constructive about this. } this.packetSequence = -1;