MySQL Connector/J 5.1 Developer Guide
Connector/J can encrypt all data communicated between the JDBC driver and the server (except for the initial handshake) using SSL. There is a performance penalty for enabling connection encryption, the severity of which depends on multiple factors including (but not limited to) the size of the query, the amount of data returned, the server hardware, the SSL library used, the network bandwidth, and so on.
The system works through two Java keystore files: one file
contains the certificate information for the server
(truststore
in the examples below), and
another contains the keys and certificate for the client
(keystore
in the examples below). All Java
keystore files are protected by the password supplied to the
keytool when you created the files. You need
the file names and the associated passwords to create an SSL
connection.
For SSL support to work, you must have the following:
A MySQL server that supports SSL, and compiled and configured to do so. For more information, see Using Encrypted Connections and Configuring SSL Library Support.
A signed client certificate, if using mutual (two-way) authentication.
By default, Connector/J establishes secure connections with the MySQL servers. Note that MySQL servers 5.7 and 8.0, when compiled with OpenSSL, can automatically generate missing SSL files at startup and configure the SSL connection accordingly.
As long as the server is correctly configured to use SSL, there
is no need to configure anything on the Connector/J client to
use encrypted connections (the exception is when Connector/J is
connecting to very old server versions like 5.6.25 and earlier
or 5.7.5 and earlier, in which case the client must set the
connection property useSSL=true
in order to
use encrypted connections). The client can demand SSL to be used
by setting the connection property
requireSSL=true
; the connection then fails if
the server is not configured to use SSL. Without
requireSSL=true
, the connection just falls
back to non-encrypted mode if the server is not configured to
use SSL.
For additional security, you can setup the client for a one-way (server or client) or two-way (server and client) SSL authentication, allowing the client or the server to authenticate each other's identity.
Server authentication via server certificate verification is
enabled when the Connector/J connection property
verifyServerCertificate
is
true
(which is the default setting when
useSSL=true
).
Standard Java SSL sockets do not support hostname verification, thus Connector/J does not support it. Host authentication is by certificates only.
Certificates signed by a trusted CA.
When verifyServerCertificate=true
(which is
the default when useSSL
is true), if no
additional configurations are made regarding server
authentication, Java verifies the server certificate using its
default trusted CA certificates, usually from
$JAVA_HOME/lib/security/cacerts
.
Using self-signed certificates. It is pretty common though for MySQL server certificates to be self signed or signed by a self-signed CA certificate; the auto-generated certificates and keys created by the MySQL server are based on the latter—that is, the server generates all required keys and a self-signed CA certificate that is used to sign a server and a client certificate. The server then configures itself to use the CA certificate and the server certificate. Although the client certificate file is placed in the same directory, it is not used by the server.
To verify the server certificate, Connector/J needs to be able
to read the certificate that signed it, that is, the server
certificate that signed itself or the self-signed CA
certificate. This can be accomplished by either importing the
certificate (ca.pem
or any other
certificate) into the Java default truststore (although
tampering the default truststore is not recommended) or by
importing it into a custom Java truststore file and configuring
the Connector/J driver accordingly. Use Java's keytool
(typically located in the bin
subdirectory
of your JDK or JRE installation) to import the server
certificates:
shell> keytool -importcert -alias MySQLCACert
-file ca.pem \
-keystore truststore -storepass mypassword
Supply the proper arguments for the command options. If the truststore file does not already exist, a new one will be created; otherwise the certificate will be added to the existing file. Interaction with keytool looks like this:
Owner: CN=MySQL_Server_5.7.17_Auto_Generated_CA_Certificate Issuer: CN=MySQL_Server_5.7.17_Auto_Generated_CA_Certificate Serial number: 1 Valid from: Thu Feb 16 11:42:43 EST 2017 until: Sun Feb 14 11:42:43 EST 2027 Certificate fingerprints: MD5: 18:87:97:37:EA:CB:0B:5A:24:AB:27:76:45:A4:78:C1 SHA1: 2B:0D:D9:69:2C:99:BF:1E:2A:25:4E:8D:2D:38:B8:70:66:47:FA:ED SHA256: C3:29:67:1B:E5:37:06:F7:A9:93:DF:C7:B3:27:5E:09:C7:FD:EE:2D:18:86:F4:9C:40:D8:26:CB:DA:95:A0:24 Signature algorithm name: SHA256withRSA Subject Public Key Algorithm: 2048-bit RSA key Version: 1 Trust this certificate? [no]: yes Certificate was added to keystore
The output of the command shows all details about the imported certificate. Make sure you remember the password you have supplied. Also, be mindful that the password will have to be written as plain text in your Connector/J configuration file or application source code.
The next step is to configure Java or Connector/J to read the truststore you just created or modified. This can be done by using one of the following three methods:
Using the Java command line arguments:
-Djavax.net.ssl.trustStore=path_to_truststore_file
-Djavax.net.ssl.trustStorePassword=mypassword
Setting the system properties directly in the client code:
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file
"); System.setProperty("javax.net.ssl.trustStorePassword","mypassword
");
Setting the Connector/J connection properties:
clientCertificateKeyStoreUrl=file:path_to_truststore_file
clientCertificateKeyStorePassword=mypassword
Notice that when used together, the connection properties override the values set by the other two methods. Also, whatever values set with connection properties are used in that connection only, while values set using the system-wide values are used for all connections (unless overridden by the connection properties).
With the above setup and the connection property
verifyServerCertificate=true
, all connections
established are going to be SSL-encrypted, with the server being
authenticated in the SSL handshake process, and the client can
now safely trust the server it is connecting to.
The server may want to authenticate a client and require the client to provide an SSL certificate to it, which it verifies against its known certificate authorities or performs additional checks on the client identity if needed (see CREATE USER SSL/TLS Options for details). In that case, Connector/J needs to have access to the client certificate, so it can be sent to the server while establishing new database connections. This is done using the Java keystore files.
To allow client authentication, the client connecting to the server must have its own set of keys and an SSL certificate. The client certificate must be signed so that the server can verify it. While you can have the client certificates signed by official certificate authorities, it is more common to use an intermediate, private, CA certificate to sign client certificates. Such an intermediate CA certificate may be self-signed or signed by a trusted root CA. The requirement is that the server knows a CA certificate that is capable of validating the client certificate.
Some MySQL server builds are able to generate SSL keys and
certificates for communication encryption, including a
certificate and a private key (contained in the
client-cert.pem
and
client-key.pem
files), which can be used by
any client. This SSL certificate is already signed by the
self-signed CA certificate ca.pem
, which
the server may have already been configured to use.
If you do not want to use the client keys and certificate files generated by the server, you can also generate new ones using the procedures described in Creating SSL and RSA Certificates and Keys. Notice that, according to the setup of the server, you may have to reuse the already existing CA certificate the server is configured to work with to sign the new client certificate, instead of creating a new one.
Once you have the client private key and certificate files you want to use, you need to import them into a Java keystore so that they can be used by the Java SSL library and Connector/J. The following instructions explain how to create the keystore file:
Convert the client key and certificate files to a PKCS #12 archive:
shell> openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem \
-name "mysqlclient
" -passout pass:mypassword
-out client-keystore.p12
Import the client key and certificate into a Java keystore:
shell> keytool -importkeystore -srckeystore client-keystore.p12
-srcstoretype pkcs12 \
-srcstorepass mypassword
-destkeystore keystore -deststoretype JKS -deststorepass mypassword
Supply the proper arguments for the command options. If the keystore file does not already exist, a new one will be created; otherwise the certificate will be added to the existing file. Output by keytool looks like this:
Entry for alias mysqlclient successfully imported. Import command completed: 1 entries successfully imported, 0 entries failed or cancelled
Make sure you remember the password you have chosen. Also, be mindful that the password will have to be written as plain text in your Connector/J configuration file or application source code.
After the step, you can delete the PKCS #12 archive
(
in the example).
client-keystore.p12
The next step is to configure Java or Connector/J so that it reads the truststore you just created or modified. This can be done by using one of the following three methods:
Using the Java command line arguments:
-Djavax.net.ssl.keyStore=path_to_keystore_file
-Djavax.net.ssl.keyStorePassword=mypassword
Setting the system properties directly in the client code:
System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file
"); System.setProperty("javax.net.ssl.keyStorePassword","mypassword
");
Through Connector/J connection properties:
clientCertificateKeyStoreUrl=file:path_to_truststore_file
clientCertificateKeyStorePassword=mypassword
Notice that when used together, the connection properties override the values set by the other two methods. Also, whatever values set with connection properties are used in that connection only, while values set using the system-wide values are used for all connections (unless overridden by the connection properties).
With the above setups , all connections established are going to be SSL-encrypted with the client being authenticated in the SSL handshake process, and the server can now safely trust the client that is requesting a connection to it.
Apply the steps outlined in both Setting up Server Authentication and Setting up Client Authentication to set up a mutual, two-way authentication process in which the server and the client authenticate each other before establishing a connection.
Although the typical setup described above uses the same CA certificate in both ends for mutual authentication, it does not have to be the case. The only requirements are that the CA certificate configured in the server must be able to validate the client certificate and the CA certificate imported into the client truststore must be able to validate the server certificate; the two CA certificates used on the two ends can be distinct.
JSSE provides debugging information to stdout
when you set the system property
-Djavax.net.debug=all
. Java then tells you
what keystores and truststores are being used, as well as what
is going on during the SSL handshake and certificate exchange.
That will be helpful when you are trying to debug a failed SSL
connection.