Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/com/mysql/jdbc/ConnectionProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,10 @@ public interface ConnectionProperties {

public void setEnabledSSLCipherSuites(String cipherSuites);

public String getEnabledTLSProtocols();

public void setEnabledTLSProtocols(String protocols);

public boolean getEnableEscapeProcessing();

public void setEnableEscapeProcessing(boolean flag);
Expand Down
11 changes: 11 additions & 0 deletions src/com/mysql/jdbc/ConnectionPropertiesImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,9 @@ protected static DriverPropertyInfo[] exposeAsDriverPropertyInfo(Properties info
private StringConnectionProperty enabledSSLCipherSuites = new StringConnectionProperty("enabledSSLCipherSuites", null,
Messages.getString("ConnectionProperties.enabledSSLCipherSuites"), "5.1.35", SECURITY_CATEGORY, 11);

private StringConnectionProperty enabledTLSProtocols = new StringConnectionProperty("enabledTLSProtocols", null,
Messages.getString("ConnectionProperties.enabledTLSProtocols"), "5.1.44", SECURITY_CATEGORY, 12);

private BooleanConnectionProperty enableEscapeProcessing = new BooleanConnectionProperty("enableEscapeProcessing", true,
Messages.getString("ConnectionProperties.enableEscapeProcessing"), "5.1.37", PERFORMANCE_CATEGORY, Integer.MIN_VALUE);

Expand Down Expand Up @@ -4948,6 +4951,14 @@ public void setEnabledSSLCipherSuites(String cipherSuites) {
this.enabledSSLCipherSuites.setValue(cipherSuites);
}

public String getEnabledTLSProtocols() {
return this.enabledTLSProtocols.getValueAsString();
}

public void setEnabledTLSProtocols(String protocols) {
this.enabledTLSProtocols.setValue(protocols);
}

public boolean getEnableEscapeProcessing() {
return this.enableEscapeProcessing.getValueAsBoolean();
}
Expand Down
32 changes: 29 additions & 3 deletions src/com/mysql/jdbc/ExportControlled.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
public class ExportControlled {
private static final String SQL_STATE_BAD_SSL_PARAMS = "08000";


protected static boolean enabled() {
// we may wish to un-static-ify this class this static method call may be removed entirely by the compiler
return true;
Expand All @@ -101,14 +102,39 @@ protected static void transformSocketToSSLSocket(MysqlIO mysqlIO) throws SQLExce
try {
mysqlIO.mysqlConnection = sslFact.connect(mysqlIO.host, mysqlIO.port, null);

String[] driverProtocols = new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
String enabledTLSProtocols = mysqlIO.connection.getEnabledTLSProtocols();
// allow TLSv1 and TLSv1.1 for all server versions by default
String[] configuredProtocols = new String[] {"TLSv1.1", "TLSv1"};
// if enabledTLSProtocols configuration option is set, overriding the default
// TLS version restrictions. This allows enabling TLSv1.2 for self-compiled
// MySQL versions supporting it, as well as the ability for users to restrict
// TLS connections to approved protocols (e.g., prohibiting TLSv1) on the client
// side.
if(enabledTLSProtocols != null && enabledTLSProtocols.length() > 0){
configuredProtocols = enabledTLSProtocols.split("\\s*,\\s*");
} else {
// Note that it is problematic to enable TLSv1.2 on the client side when
// the server does not support it. This appears to be the original reason
// for this code, which is left as default behavior. When TLSv1.2 is enabled
// client-side, and not supported by the server, a SSLException is thrown
// during SSLSocket.startHandshake(). This closes the SSLSocket, and the
// handshake cannot be re-attempted with a different protocol list without
// establishing a new SSLSocket.
if (mysqlIO.versionMeetsMinimum(5, 6, 0) && Util.isEnterpriseEdition(mysqlIO.getServerVersion())) {
configuredProtocols = new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
}
}
List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(configuredProtocols));
List<String> allowedProtocols = new ArrayList<String>();

List<String> supportedProtocols = Arrays.asList(((SSLSocket) mysqlIO.mysqlConnection).getSupportedProtocols());
for (String protocol : (mysqlIO.versionMeetsMinimum(5, 6, 0) && Util.isEnterpriseEdition(mysqlIO.getServerVersion())
? new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" } : new String[] { "TLSv1.1", "TLSv1" })) {
if (supportedProtocols.contains(protocol)) {
for (String protocol : driverProtocols) {
if (supportedProtocols.contains(protocol) && enabledProtocols.contains(protocol)) {
allowedProtocols.add(protocol);
}
}

((SSLSocket) mysqlIO.mysqlConnection).setEnabledProtocols(allowedProtocols.toArray(new String[0]));

// check allowed cipher suites
Expand Down
1 change: 1 addition & 0 deletions src/com/mysql/jdbc/LocalizedErrorMessages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ ConnectionProperties.detectCustomCollations=Should the driver detect custom char
ConnectionProperties.dontCheckOnDuplicateKeyUpdateInSQL=Stops checking if every INSERT statement contains the "ON DUPLICATE KEY UPDATE" clause. As a side effect, obtaining the statement's generated keys information will return a list where normally it wouldn't. Also be aware that, in this case, the list of generated keys returned may not be accurate. The effect of this property is canceled if set simultaneously with 'rewriteBatchedStatements=true'.
ConnectionProperties.readOnlyPropagatesToServer=Should the driver issue appropriate statements to implicitly set the transaction access mode on server side when Connection.setReadOnly() is called? Setting this property to 'true' enables InnoDB read-only potential optimizations but also requires an extra roundtrip to set the right transaction state. Even if this property is set to 'false', the driver will do its best effort to prevent the execution of database-state-changing queries. Requires minimum of MySQL 5.6.
ConnectionProperties.enabledSSLCipherSuites=If "useSSL" is set to "true", overrides the cipher suites enabled for use on the underlying SSL sockets. This may be required when using external JSSE providers or to specify cipher suites compatible with both MySQL server and used JVM.
ConnectionProperties.enabledTLSProtocols=If "useSSL" is set to "true", overrides the TLS protocols enabled for use on the underlying SSL sockets. This may be used to restrict connections to specific TLS versions.
ConnectionProperties.enableEscapeProcessing=Sets the default escape processing behavior for Statement objects. The method Statement.setEscapeProcessing() can be used to specify the escape processing behavior for an individual Statement object. Default escape processing behavior in prepared statements must be defined with the property 'processEscapeCodesForPrepStmts'.

#
Expand Down
8 changes: 8 additions & 0 deletions src/com/mysql/jdbc/MultiHostMySQLConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -2479,6 +2479,14 @@ public void setEnabledSSLCipherSuites(String cipherSuites) {
getActiveMySQLConnection().setEnabledSSLCipherSuites(cipherSuites);
}

public String getEnabledTLSProtocols() {
return getActiveMySQLConnection().getEnabledTLSProtocols();
}

public void setEnabledTLSProtocols(String protocols) {
getActiveMySQLConnection().setEnabledTLSProtocols(protocols);
}

public boolean getEnableEscapeProcessing() {
return getActiveMySQLConnection().getEnableEscapeProcessing();
}
Expand Down
8 changes: 8 additions & 0 deletions src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2882,6 +2882,14 @@ public void setEnabledSSLCipherSuites(String cipherSuites) {
this.mc.setEnabledSSLCipherSuites(cipherSuites);
}

public String getEnabledTLSProtocols() {
return this.mc.getEnabledTLSProtocols();
}

public void setEnabledTLSProtocols(String protocols) {
this.mc.setEnabledTLSProtocols(protocols);
}

public boolean getEnableEscapeProcessing() {
return this.mc.getEnableEscapeProcessing();
}
Expand Down
83 changes: 82 additions & 1 deletion src/testsuite/regression/ConnectionRegressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
Expand Down Expand Up @@ -8459,8 +8460,15 @@ public void testTLSVersion() throws Exception {
ResultSet rset = sslConn.createStatement().executeQuery("SHOW STATUS LIKE 'ssl_version'");
assertTrue(rset.next());
String tlsVersion = rset.getString(2);
System.out.println(tlsVersion);
System.out.println("TLS version: " + tlsVersion);
System.out.println();
System.out.println("MySQL version: " + ((MySQLConnection) sslConn).getServerVersion());
String etp = ((MySQLConnection) sslConn).getEnabledTLSProtocols();
System.out.println("enabledTLSProtocols: " + etp);
System.out.println();
System.out.println("JVM version: " + Util.getJVMVersion());
System.out.println();


if (((MySQLConnection) sslConn).versionMeetsMinimum(5, 7, 10) && Util.getJVMVersion() > 6) {
if (Util.isEnterpriseEdition(((MySQLConnection) sslConn).getServerVersion())) {
Expand All @@ -8476,6 +8484,79 @@ public void testTLSVersion() throws Exception {
}
}

/**
* Tests fix for Bug#87379. This allows TLS version to be overridden through a new configuration
* option - enabledTLSProtocols. When set to some combination of TLSv1, TLSv1.1, or TLSv1.2 (comma-
* separated, no spaces), the default behavior restricting the TLS version based on JRE and MySQL
* Server version is bypassed to enable or restrict specific TLS versions.
*
* This test requires community server (with yaSSL) in -Dcom.mysql.jdbc.testsuite.url and
* commercial server (with OpenSSL) in -Dcom.mysql.jdbc.testsuite.url.sha256default
*
* Test certificates from testsuite/ssl-test-certs must be installed on both servers.
*
* @throws Exception
* if the test fails.
*/
public void testEnableTLSVersion() throws Exception {

final String[] testDbUrls;
Properties props = new Properties();
props.setProperty("allowPublicKeyRetrieval", "true");
props.setProperty("useSSL", "true");
props.setProperty("requireSSL", "true");
props.setProperty("trustCertificateKeyStoreUrl", "file:src/testsuite/ssl-test-certs/ca-truststore");
props.setProperty("trustCertificateKeyStoreType", "JKS");
props.setProperty("trustCertificateKeyStorePassword", "password");

if (this.sha256Conn != null && ((MySQLConnection) this.sha256Conn).versionMeetsMinimum(5, 5, 7)) {
testDbUrls = new String[] { BaseTestCase.dbUrl, sha256Url };
} else {
testDbUrls = new String[] { BaseTestCase.dbUrl };
}

for (String testDbUrl : testDbUrls) {
System.out.println(testDbUrl);
System.out.println(System.getProperty("java.version"));
Connection sslConn = getConnectionWithProps(testDbUrl, props);
assertTrue(((MySQLConnection) sslConn).getIO().isSSLEstablished());
List<String> expectedProtocols = new ArrayList<String>();
expectedProtocols.add("TLSv1");
if (Util.getJVMVersion() > 6 && ((MySQLConnection) sslConn).versionMeetsMinimum(5, 7, 10)) {
ResultSet rs = sslConn.createStatement().executeQuery("SELECT @@global.tls_version");
assertTrue(rs.next());
String supportedTLSVersions = rs.getString(1);
System.out.println("Server reported TLS version support: " + supportedTLSVersions);
expectedProtocols.addAll(Arrays.asList(supportedTLSVersions.split("\\s*,\\s*")));
}

String[] testingProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1" };
for (String protocol : testingProtocols) {
Properties testProps = new Properties();
testProps.putAll(props);
testProps.put("enabledTLSProtocols", protocol);
System.out.println("Testing " + protocol + " expecting connection: " + expectedProtocols.contains(protocol));
try {
Connection tlsConn = getConnectionWithProps(testProps);
if(!expectedProtocols.contains(protocol)){
fail("Expected to fail connection with " + protocol + " due to lack of server support.");
}
ResultSet rset = tlsConn.createStatement().executeQuery("SHOW STATUS LIKE 'ssl_version'");
assertTrue(rset.next());
String tlsVersion = rset.getString(2);
assertEquals(protocol,tlsVersion);
tlsConn.close();
} catch (Exception e) {
if (expectedProtocols.contains(protocol)) {
fail("Expected to be able to connect with " + protocol + " protocol, but failed.");
}
}

}

sslConn.close();
}
}
/**
* Tests fix for Bug#21286268 - CONNECTOR/J REPLICATION USE MASTER IF SLAVE IS UNAVAILABLE.
*/
Expand Down