92
92
import com .mysql .cj .conf .PropertyDefinitions .SslMode ;
93
93
import com .mysql .cj .conf .PropertyKey ;
94
94
import com .mysql .cj .conf .PropertySet ;
95
+ import com .mysql .cj .conf .RuntimeProperty ;
95
96
import com .mysql .cj .exceptions .CJCommunicationsException ;
96
97
import com .mysql .cj .exceptions .ExceptionFactory ;
97
98
import com .mysql .cj .exceptions .ExceptionInterceptor ;
98
99
import com .mysql .cj .exceptions .FeatureNotAvailableException ;
99
100
import com .mysql .cj .exceptions .RSAException ;
100
101
import com .mysql .cj .exceptions .SSLParamsException ;
101
- import com .mysql .cj .exceptions .WrongArgumentException ;
102
102
import com .mysql .cj .log .Log ;
103
103
import com .mysql .cj .util .Base64Decoder ;
104
104
import com .mysql .cj .util .StringUtils ;
105
- import com .mysql .cj .util .Util ;
106
105
107
106
/**
108
107
* Holds functionality that falls under export-control regulations.
@@ -112,7 +111,8 @@ public class ExportControlled {
112
111
private static final String TLSv1_1 = "TLSv1.1" ;
113
112
private static final String TLSv1_2 = "TLSv1.2" ;
114
113
private static final String TLSv1_3 = "TLSv1.3" ;
115
- private static final String [] TLS_PROTOCOLS = new String [] { TLSv1_3 , TLSv1_2 , TLSv1_1 , TLSv1 };
114
+ private static final String [] KNOWN_TLS_PROTOCOLS = new String [] { TLSv1_3 , TLSv1_2 , TLSv1_1 , TLSv1 };
115
+ private static final String [] VALID_TLS_PROTOCOLS = new String [] { TLSv1_3 , TLSv1_2 };
116
116
117
117
private static final String TLS_SETTINGS_RESOURCE = "/com/mysql/cj/TlsSettings.properties" ;
118
118
private static final List <String > ALLOWED_CIPHERS = new ArrayList <>();
@@ -150,7 +150,7 @@ public static boolean enabled() {
150
150
}
151
151
152
152
private static String [] getAllowedCiphers (PropertySet pset , List <String > socketCipherSuites ) {
153
- String enabledSSLCipherSuites = pset .getStringProperty (PropertyKey .enabledSSLCipherSuites ).getValue ();
153
+ String enabledSSLCipherSuites = pset .getStringProperty (PropertyKey .tlsCiphersuites ).getValue ();
154
154
Stream <String > filterStream = StringUtils .isNullOrEmpty (enabledSSLCipherSuites ) ? socketCipherSuites .stream ()
155
155
: Arrays .stream (enabledSSLCipherSuites .split ("\\ s*,\\ s*" )).filter (socketCipherSuites ::contains );
156
156
@@ -165,54 +165,66 @@ private static String[] getAllowedCiphers(PropertySet pset, List<String> socketC
165
165
return allowedCiphers .toArray (new String [] {});
166
166
}
167
167
168
- private static String [] getAllowedProtocols (PropertySet pset , ServerVersion serverVersion , String [] socketProtocols ) {
169
- String [] tryProtocols = null ;
168
+ private static String [] getAllowedProtocols (PropertySet pset , @ SuppressWarnings ( "unused" ) ServerVersion serverVersion , String [] socketProtocols ) {
169
+ List < String > tryProtocols = null ;
170
170
171
- // If enabledTLSProtocols configuration option is set, overriding the default TLS version restrictions.
172
- // This allows enabling TLSv1.2 for self-compiled MySQL versions supporting it, as well as the ability
173
- // for users to restrict TLS connections to approved protocols (e.g., prohibiting TLSv1) on the client side.
174
- String enabledTLSProtocols = pset .getStringProperty (PropertyKey .enabledTLSProtocols ).getValue ();
175
- if (enabledTLSProtocols != null && enabledTLSProtocols .length () > 0 ) {
176
- tryProtocols = enabledTLSProtocols .split ("\\ s*,\\ s*" );
177
- }
178
- // It is problematic to enable TLSv1.2 on the client side when the server is compiled with yaSSL. When client attempts to connect with
179
- // TLSv1.2 yaSSL just closes the socket instead of re-attempting handshake with lower TLS version. So here we allow all protocols only
180
- // for server versions which are known to be compiled with OpenSSL.
181
- else if (serverVersion == null ) {
182
- // X Protocol doesn't provide server version, but we prefer to use most recent TLS version, though it also means that X Protocol
183
- // connection to old MySQL 5.7 GPL releases will fail by default, user must use enabledTLSProtocols=TLSv1.1 to connect them.
184
- tryProtocols = TLS_PROTOCOLS ;
185
- } else if (serverVersion .meetsMinimum (new ServerVersion (5 , 7 , 28 ))
186
- || serverVersion .meetsMinimum (new ServerVersion (5 , 6 , 46 )) && !serverVersion .meetsMinimum (new ServerVersion (5 , 7 , 0 ))
187
- || serverVersion .meetsMinimum (new ServerVersion (5 , 6 , 0 )) && Util .isEnterpriseEdition (serverVersion .toString ())) {
188
- tryProtocols = TLS_PROTOCOLS ;
171
+ RuntimeProperty <String > tlsVersions = pset .getStringProperty (PropertyKey .tlsVersions );
172
+ if (tlsVersions != null && tlsVersions .isExplicitlySet ()) {
173
+ // If tlsVersions configuration option is set then override the default TLS versions restriction.
174
+ if (tlsVersions .getValue () == null ) {
175
+ throw ExceptionFactory .createException (SSLParamsException .class ,
176
+ "Specified list of TLS versions is empty. Accepted values are TLSv1.2 and TLSv1.3." );
177
+ }
178
+ tryProtocols = getValidProtocols (tlsVersions .getValue ().split ("\\ s*,\\ s*" ));
189
179
} else {
190
- // allow only TLSv1 and TLSv1.1 for other server versions by default
191
- tryProtocols = new String [] { TLSv1_1 , TLSv1 };
180
+ tryProtocols = new ArrayList <>(Arrays .asList (VALID_TLS_PROTOCOLS ));
192
181
}
193
182
194
- List <String > configuredProtocols = new ArrayList <>(Arrays .asList (tryProtocols ));
195
183
List <String > jvmSupportedProtocols = Arrays .asList (socketProtocols );
196
-
197
184
List <String > allowedProtocols = new ArrayList <>();
198
- for (String protocol : TLS_PROTOCOLS ) {
199
- if (jvmSupportedProtocols .contains (protocol ) && configuredProtocols . contains ( protocol ) ) {
185
+ for (String protocol : tryProtocols ) {
186
+ if (jvmSupportedProtocols .contains (protocol )) {
200
187
allowedProtocols .add (protocol );
201
188
}
202
189
}
203
190
return allowedProtocols .toArray (new String [0 ]);
204
-
205
191
}
206
192
207
- public static void checkValidProtocols (List <String > protocols ) {
208
- List <String > validProtocols = Arrays .asList (TLS_PROTOCOLS );
209
- for (String protocol : protocols ) {
210
- if (!validProtocols .contains (protocol )) {
211
- throw ExceptionFactory .createException (WrongArgumentException .class ,
212
- "'" + protocol + "' not recognized as a valid TLS protocol version (should be one of "
213
- + Arrays .stream (TLS_PROTOCOLS ).collect (Collectors .joining (", " )) + ")." );
193
+ private static List <String > getValidProtocols (String [] protocols ) {
194
+
195
+ List <String > requestedProtocols = Arrays .stream (protocols ).filter (p -> !StringUtils .isNullOrEmpty (p .trim ())).collect (Collectors .toList ());
196
+ if (requestedProtocols .size () == 0 ) {
197
+ throw ExceptionFactory .createException (SSLParamsException .class ,
198
+ "Specified list of TLS versions is empty. Accepted values are TLSv1.2 and TLSv1.3." );
199
+ }
200
+
201
+ List <String > sanitizedProtocols = new ArrayList <>();
202
+ for (String protocol : KNOWN_TLS_PROTOCOLS ) {
203
+ if (requestedProtocols .contains (protocol )) {
204
+ sanitizedProtocols .add (protocol );
214
205
}
215
206
}
207
+ if (sanitizedProtocols .size () == 0 ) {
208
+ throw ExceptionFactory .createException (SSLParamsException .class ,
209
+ "Specified list of TLS versions only contains non valid TLS protocols. Accepted values are TLSv1.2 and TLSv1.3." );
210
+ }
211
+
212
+ List <String > validProtocols = new ArrayList <>();
213
+ for (String protocol : VALID_TLS_PROTOCOLS ) {
214
+ if (sanitizedProtocols .contains (protocol )) {
215
+ validProtocols .add (protocol );
216
+ }
217
+ }
218
+ if (validProtocols .size () == 0 ) {
219
+ throw ExceptionFactory .createException (SSLParamsException .class ,
220
+ "TLS protocols TLSv1 and TLSv1.1 are not supported. Accepted values are TLSv1.2 and TLSv1.3." );
221
+ }
222
+
223
+ return validProtocols ;
224
+ }
225
+
226
+ public static void checkValidProtocols (List <String > protocols ) {
227
+ getValidProtocols (protocols .toArray (new String [0 ]));
216
228
}
217
229
218
230
private static class KeyStoreConf {
@@ -333,14 +345,6 @@ public static Socket performTlsHandshake(Socket rawSocket, SocketConnection sock
333
345
}
334
346
335
347
sslSocket .startHandshake ();
336
-
337
- if (log != null ) {
338
- String tlsVersion = sslSocket .getSession ().getProtocol ();
339
- if (TLSv1 .equalsIgnoreCase (tlsVersion ) || TLSv1_1 .equalsIgnoreCase (tlsVersion )) {
340
- log .logWarn ("This connection is using " + tlsVersion + " which is now deprecated and will be removed in a future release of Connector/J." );
341
- }
342
- }
343
-
344
348
return sslSocket ;
345
349
}
346
350
0 commit comments