/*
 * Copyright DataStax, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.oss.driver.internal.core.ssl;

import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
import com.datastax.oss.driver.api.core.context.DriverContext;
import com.datastax.oss.driver.api.core.metadata.EndPoint;
import com.datastax.oss.driver.api.core.ssl.SslEngineFactory;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;
import net.jcip.annotations.ThreadSafe;

Default SSL implementation.

To activate this class, add an advanced.ssl-engine-factory section in the driver configuration, for example:

datastax-java-driver {
  advanced.ssl-engine-factory {
    class = DefaultSslEngineFactory
    cipher-suites = [ "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA" ]
    hostname-validation = false
    truststore-path = /path/to/client.truststore
    truststore-password = password123
    keystore-path = /path/to/client.keystore
    keystore-password = password123
  }
}
See reference.conf (in the manual or core driver JAR) for more details.
/** * Default SSL implementation. * * <p>To activate this class, add an {@code advanced.ssl-engine-factory} section in the driver * configuration, for example: * * <pre> * datastax-java-driver { * advanced.ssl-engine-factory { * class = DefaultSslEngineFactory * cipher-suites = [ "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA" ] * hostname-validation = false * truststore-path = /path/to/client.truststore * truststore-password = password123 * keystore-path = /path/to/client.keystore * keystore-password = password123 * } * } * </pre> * * See {@code reference.conf} (in the manual or core driver JAR) for more details. */
@ThreadSafe public class DefaultSslEngineFactory implements SslEngineFactory { private final SSLContext sslContext; private final String[] cipherSuites; private final boolean requireHostnameValidation;
Builds a new instance from the driver configuration.
/** Builds a new instance from the driver configuration. */
public DefaultSslEngineFactory(DriverContext driverContext) { DriverExecutionProfile config = driverContext.getConfig().getDefaultProfile(); try { this.sslContext = buildContext(config); } catch (Exception e) { throw new IllegalStateException("Cannot initialize SSL Context", e); } if (config.isDefined(DefaultDriverOption.SSL_CIPHER_SUITES)) { List<String> list = config.getStringList(DefaultDriverOption.SSL_CIPHER_SUITES); String tmp[] = new String[list.size()]; this.cipherSuites = list.toArray(tmp); } else { this.cipherSuites = null; } this.requireHostnameValidation = config.getBoolean(DefaultDriverOption.SSL_HOSTNAME_VALIDATION, true); } @NonNull @Override public SSLEngine newSslEngine(@NonNull EndPoint remoteEndpoint) { SSLEngine engine; SocketAddress remoteAddress = remoteEndpoint.resolve(); if (remoteAddress instanceof InetSocketAddress) { InetSocketAddress socketAddress = (InetSocketAddress) remoteAddress; engine = sslContext.createSSLEngine(socketAddress.getHostName(), socketAddress.getPort()); } else { engine = sslContext.createSSLEngine(); } engine.setUseClientMode(true); if (cipherSuites != null) { engine.setEnabledCipherSuites(cipherSuites); } if (requireHostnameValidation) { SSLParameters parameters = engine.getSSLParameters(); parameters.setEndpointIdentificationAlgorithm("HTTPS"); engine.setSSLParameters(parameters); } return engine; } protected SSLContext buildContext(DriverExecutionProfile config) throws Exception { if (config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PATH) || config.isDefined(DefaultDriverOption.SSL_TRUSTSTORE_PATH)) { SSLContext context = SSLContext.getInstance("SSL"); // initialize truststore if configured. TrustManagerFactory tmf = null; if (config.isDefined(DefaultDriverOption.SSL_TRUSTSTORE_PATH)) { try (InputStream tsf = Files.newInputStream( Paths.get(config.getString(DefaultDriverOption.SSL_TRUSTSTORE_PATH)))) { KeyStore ts = KeyStore.getInstance("JKS"); char[] password = config.isDefined(DefaultDriverOption.SSL_TRUSTSTORE_PASSWORD) ? config.getString(DefaultDriverOption.SSL_TRUSTSTORE_PASSWORD).toCharArray() : null; ts.load(tsf, password); tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ts); } } // initialize keystore if configured. KeyManagerFactory kmf = null; if (config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PATH)) { try (InputStream ksf = Files.newInputStream( Paths.get(config.getString(DefaultDriverOption.SSL_KEYSTORE_PATH)))) { KeyStore ks = KeyStore.getInstance("JKS"); char[] password = config.isDefined(DefaultDriverOption.SSL_KEYSTORE_PASSWORD) ? config.getString(DefaultDriverOption.SSL_KEYSTORE_PASSWORD).toCharArray() : null; ks.load(ksf, password); kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, password); } } context.init( kmf != null ? kmf.getKeyManagers() : null, tmf != null ? tmf.getTrustManagers() : null, new SecureRandom()); return context; } else { // if both keystore and truststore aren't configured, use default SSLContext. return SSLContext.getDefault(); } } @Override public void close() throws Exception { // nothing to do } }