Skip to main content

Configuring Java Clients to Use TLS with InterSystems IRIS

You can configure a Java client application to use TLS when it communicates with InterSystems IRIS® data platform. This communication occurs through the superserver, so a related required step is setting up the superserver to use TLS; this is described in Configuring the InterSystems IRIS Superserver to Use TLS. Java clients can be implemented using either JDBC or object bindings.

The process for configuring a Java client application to use TLS with InterSystems IRIS is:

  1. Determine if the client requires a keystore or a truststore. This depends on several factors: whether or not the InterSystems IRIS server requests or requires client authentication; whether server authentication is required; and the cipher suites in use. See “Determine the Need for a Keystore and a Truststore” for more information.

  2. Create a configuration file with properties in it to provide those features. See “Create a Client Configuration” for more information.

  3. In the code for the client application, optionally specify the name of the client configuration; if you do not specify a name, Java uses the default configuration information. See “Specify the Use of the Client Configuration” for more information.

Determine the Need for a Keystore and a Truststore

A keystore serves as a repository for the client’s private key, public key certificate, and any Certificate Authority (CA) information. This information is needed (1) if the InterSystems IRIS server requires client authentication or (2) if the cipher suite in use requires a client key pair:

  • Whether or not the InterSystems IRIS server requires client authentication is determined by the choice for the Peer certificate verification level field on the Edit SSL/TLS Configuration page for that InterSystems IRIS instance’s “%SuperServer” TLS configuration. If the field has a value of Require, the client must have a certificate; if the field has a value of Request, the server checks a certificate if one is available.

  • The client and server agree upon a cipher suite to use. This cipher suite determines whether or not there is a client certificate, a key pair, or both. The enabled server cipher suites are determined by the value of the Enabled ciphersuites field on the Edit SSL/TLS Configuration page for that InterSystems IRIS instance’s “%SuperServer” TLS configuration. The cipher suites available to the client depend on the version of Java it is using.

If the client has a private key and certificate, these are stored in the client’s keystore; the keystore can also hold the client’s root CA certificate and any intermediate CA certificates. To authenticate the server, the client may need to have the root CA certificate for the server and any intermediate CA certificates, these can be stored either in the client’s truststore or along with client certificate information in the keystore. For more information on keystores and truststores, see the section “Keystores and Truststores” in the Java Secure Socket Extension (JSSE) Reference Guide.

Create a Client Configuration

The behavior of a Java client depends on the values of properties in its configuration. The configuration gets these values from what is known as a “configuration file,” either from the configuration file’s default values or from its configuration-specific values. The following sections describe how configuration files work:

Configuration Files, Configurations, Properties, Values, and Defaults

Each configuration file specifies values for the properties that one or more configurations use. The file includes both default values and configuration-specific values, in the form of name-value pairs. Generally, unversioned property names specify default values for properties and versioned property names specify configuration-specific values.

If a configuration file contains only one configuration definition, that single configuration can use unversioned properties. However, it cannot have an associated name property. Without a named configuration, invoke the configuration without specifying a name (as described in “Specify the Use of the Client Configuration” and “Specify a Configuration without a Name”).

If a configuration file contains multiple configurations, each configuration is defined by the existence of a numbered version of the name property of the form name.n, where n is the number of the configuration. The names of a configuration’s other properties use the same version number as the name property, so that they have a form of propertyname.n where propertyname is the name of the property and n is the number of the configuration.

The definitions in a configuration file are case-sensitive. Their use of spaces is flexible. The order of property definitions is also flexible.

To specify the default value of a property for use by all configurations, specify an unversioned property name and its value in the following form:

propertyName = propertyValue

For example, to specify the default value for the keyStoreType property as pkcs12, the form is:

keyStoreType = pkcs12

To override the default value for a property, specify a versioned property name, such as:

keyStoreType.1 = jceks

If a configuration file contains multiple configuration definitions, then these versions must use sequential ordering; if client application code refers to a configuration that follows a sequential gap, then an error results. For example, suppose that a configuration file has three versioned name properties: name.1, name.2, and name.4; the configuration associated with the name.4 property will not ever be created and a reference to it will fail with an error.

Java Client Configuration Properties

The properties are:

  • cipherSuites — A comma-delimited list of supported cipher suites. The available cipher suites depend on the JRE (Java Runtime Environment) on the machine. During the TLS handshake, the server selects the strongest cipher suite that both it and the client support. [Optional]

  • debug — Whether or not debugging information is logged to the Java system.err file. This property can have a value of true or false (false is the default). The setting of this property has no effect on exception handling. [Optional]

  • keyRecoveryPassword — Password used to access the client’s private key; this was created at the same time as the private key pair. [Required if the private key has password protections and application code is not passing in the private key as an input parameter.]

  • keyStore — The file for storing the client private key and certificate information. The keystore can also hold the content typically associated with the truststore. [Optional]

  • keyStorePassword — Password to gain access to the keystore. [Required if a password was specified when the keystore was created.]

  • keyStoreType — The format of the keystore file, if one is specified. [Optional]

    Supported formats are:

    • jks — Java KeyStore, the Java proprietary format. [Default]

    • jceks — Java Cryptography Extension KeyStore format.

    • pkcs12 — Public Key Certificate Standard #12 format.

  • logFile — The file in which Java records errors. [Optional]

  • name — A versioned identifier for the Java client configuration. (Each name property must be versioned. Any unversioned name property is not meaningful and is ignored.) [Optional]

    If the configuration file specifies only a single configuration and only uses unversioned property names, the name property is not required (as described in “Specify the Use of the Client Configuration”). For information about specifying multiple configurations with a single configuration file, see Configuration Files, Configurations, Properties, Values, and Defaults).

  • protocol — The version of the TLS protocol to be used for the connection. [Required]

    Supported values include:

    • TLS — Any version of the TLS protocol. During the TLS handshake, the server selects the latest (most recent) version of the protocol that it supports. [Default]

    • TLSv1 — Version 1 of TLS.

    • TLSv1.1 — Version 1.1 of TLS.

    • TLSv1.2 — Version 1.2 of TLS.

  • trustStore — The file for storing the server’s root CA certificate; it can also hold the certificates for any intermediate CAs. (This information can also be placed in the keystore.) [Optional]

  • trustStorePassword — Password to gain access to the truststore. [Required if a password was specified when the keystore was created.]

  • trustStoreType — The format of the truststore file, if one is specified. [Optional]

    Supported formats are:

    • jks — Java KeyStore, the Java proprietary format. [Default]

    • jceks — Java Cryptography Extension KeyStore format.

    • pkcs12 — Public Key Certificate Standard #12 format.

A Sample Configuration File

The following is a sample configuration file for use with a Java client:

debug = false
logFile = javatls.log
protocol = TLSv1.2
cipherSuites = TLS_AES_256_GCM_SHA384
keyStoreType = JKS
keyStore = keystore.jks
keyRecoveryPassword = <password>
keyStorePassword = <password>
trustStoreType = JKS
trustStore = truststore.jks
trustStorePassword = <password>
trustStoreRecoveryPassword = <password>

name.1 = IRISJavaClient1
keyStorePassword.1 = <password>
keyRecoveryPassword.1 = <password>
trustStorePassword.1 = <password>
trustStoreRecoveryPassword.1 = <password>

name.2 = IRISJavaClient2
protocol.2 = TLS
keyStoreType.2 = pkcs12
keyStore.2 = keystore.p12
keyStorePassword.2 = <password>
trustStore.2 = cjc1.ts
trustStorePassword.2 = <password>

Name the Configuration File

Either save the configuration file with the name SSLConfig.properties or set the value of the Java environment variable com.intersystems.SSL.ConfigFile to the name of the file. The code checks for the file in the current working directory.

Specify the Use of the Client Configuration

Once a configuration has been defined, client application code invokes it when connecting to the server. You can do this either with calls for the DriverManager object or the IRISDataSource object.

Use the DriverManager Object

With DriverManager, this involves the following steps:

  1. Creating a Java Properties object.

  2. Setting the value for various properties of that object.

  3. Passing that object to Java Connection object for the connection from the client to the InterSystems IRIS server.

To specify information for the connection, the first part of the process is to create a Properties object from a configuration file and set the values of particular properties in it. In its simplest form, the code to do this is:

java.util.Properties prop = new java.util.Properties();
prop.put("connection security level", "10");
prop.put("SSL configuration name",configName);
prop.put("key recovery password",keyPassword);

where

  • The connection security level of 10 specifies that the client is attempting use TLS to protect the connection.

  • configName is a variable whose value holds the name of Java client configuration. If the configuration file has only default values and these are being used for a single configuration, do not include this line; see Specify a Configuration without a Name for details.

  • keyPassword is the password required to extract the client’s private key from the keystore.

Once the Properties object exists and has been populated, the final step is to pass it to the connection from the InterSystems IRIS Java client to the InterSystems IRIS server. This is done in the call to the DriverManager.getConnection method. The form of this call is:

Connection conn = DriverManager.getConnection(IRISServerAddress, prop);

where IRISServerAddress is a string that specifies the address of the InterSystems IRIS server and prop is the properties object being passed to that string.

If this call succeeds, the TLS-protected connection has been established. Typically, application code containing calls such as those described in this section includes various checks for success and protection against any errors. For more details about using InterSystems IRIS Java connectivity, see Using Java JDBC with InterSystems IRIS.

Use the IRISDataSourceObject

With the IRISDataSource object, the procedure is to create the object, call its methods to set the relevant values, and establish the connection. The methods are:

  • setConnectionSecurityLevel — This method takes a single argument: a connection security level of 10, which specifies that the client is attempting use TLS to protect the connection.

  • setSSLConfigurationName — This method takes a single argument: a variable whose value holds the name of Java client configuration. If the configuration file has only default values and these are being used for a single configuration, do not include this line; see Specify a Configuration without a Name for details.

  • setKeyRecoveryPassword — This method takes a single argument: the password required to extract the client’s private key from the keystore.

In its simplest form, the code to do this is:

try{
   IRISDataSource ds = new IRISDataSource();
   
   ds.setURL("jdbc:IRIS://127.0.0.1:1972/TESTNAMESPACE");
   ds.setConnectionSecurityLevel(10);
   ds.setSSLConfigurationName(configName);
   ds.setKeyRecoveryPassword(keyPassword);

   Connection dbconnection = ds.getConnection();
}

For a complete list of the methods for getting and setting properties, see the JDBC Quick Reference. The JavaDoc for com.intersystems.jdbc.IRISDataSource is under <install-dir>/dev/java/doc/index.html

Specify a Configuration without a Name

If a configuration file contains only one configuration definition, that single configuration can use unversioned properties. However, it cannot have an associated name property.

When working with a DriverManager object, the Properties object uses only the default values from the configuration file. The code for creating this object differs from the typical case in that there is no call to specify a value for the “SSL configuration name” key:

java.util.Properties prop = new java.util.Properties();
prop.put("connection security level", "10");
prop.put("key recovery password",keyPassword);

When working with an IRISDataSource object, if you want to specify an unnamed configuration, simply do not call setSSLConfigurationName.

Feedback