[SSL/TLS] filter out unsupported ciphers before setting the cipher list
This change filters out unsupported ciphers before setting the ciphers on the SSLEngine. The unsupported ciphers are logged in a message at the error level. If none of the specified ciphers are supported, then an exception will be thrown. Closes elastic/elasticsearch#698 Original commit: elastic/x-pack-elasticsearch@68cf47ec19
This commit is contained in:
parent
6a6e44545c
commit
7cfdf521c3
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.cache.CacheBuilder;
|
||||
import org.elasticsearch.common.cache.CacheLoader;
|
||||
import org.elasticsearch.common.cache.LoadingCache;
|
||||
|
@ -16,11 +17,15 @@ import org.elasticsearch.common.settings.ImmutableSettings;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.concurrent.UncheckedExecutionException;
|
||||
import org.elasticsearch.shield.ShieldSettingsException;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This service houses the private key and trust managers needed for SSL/TLS negotiation. It is the central place to
|
||||
|
@ -92,7 +97,9 @@ public abstract class AbstractSSLService extends AbstractComponent {
|
|||
SSLEngine createSSLEngine(SSLContext sslContext, String[] ciphers, String[] supportedProtocols, String host, int port) {
|
||||
SSLEngine sslEngine = sslContext.createSSLEngine(host, port);
|
||||
try {
|
||||
sslEngine.setEnabledCipherSuites(ciphers);
|
||||
sslEngine.setEnabledCipherSuites(supportedCiphers(sslEngine.getSupportedCipherSuites(), ciphers));
|
||||
} catch (ElasticsearchException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new ElasticsearchSSLException("failed loading cipher suites [" + Arrays.asList(ciphers) + "]", t);
|
||||
}
|
||||
|
@ -105,6 +112,38 @@ public abstract class AbstractSSLService extends AbstractComponent {
|
|||
return sslEngine;
|
||||
}
|
||||
|
||||
String[] supportedCiphers(String[] supportedCiphers, String[] requestedCiphers) {
|
||||
List<String> requestedCiphersList = new ArrayList<>(requestedCiphers.length);
|
||||
List<String> unsupportedCiphers = new LinkedList<>();
|
||||
boolean found;
|
||||
for (String requestedCipher : requestedCiphers) {
|
||||
found = false;
|
||||
for (String supportedCipher : supportedCiphers) {
|
||||
if (supportedCipher.equals(requestedCipher)) {
|
||||
found = true;
|
||||
requestedCiphersList.add(requestedCipher);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
unsupportedCiphers.add(requestedCipher);
|
||||
}
|
||||
}
|
||||
|
||||
if (requestedCiphersList.isEmpty()) {
|
||||
throw new ShieldSettingsException("none of the ciphers [" + Arrays.asList(requestedCiphers) + "] are supported by this JVM");
|
||||
}
|
||||
|
||||
if (!unsupportedCiphers.isEmpty()) {
|
||||
logger.error("unsupported ciphers [{}] were requested but cannot be used in this JVM. If you are trying to use ciphers\n" +
|
||||
"with a key length greater than 128 bits on an Oracle JVM, you will need to install the unlimited strength\n" +
|
||||
"JCE policy files. Additionally, please ensure the PKCS11 provider is enabled for your JVM.", unsupportedCiphers);
|
||||
}
|
||||
|
||||
return requestedCiphersList.toArray(new String[requestedCiphersList.size()]);
|
||||
}
|
||||
|
||||
private class SSLContextCacheLoader extends CacheLoader<SSLSettings, SSLContext> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,7 +22,9 @@ import javax.net.ssl.SSLHandshakeException;
|
|||
import javax.net.ssl.SSLSessionContext;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
@ -207,4 +209,26 @@ public class ClientSSLServiceTests extends ElasticsearchTestCase {
|
|||
.build());
|
||||
sslService.sslContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validCiphersAndInvalidCiphersWork() throws Exception {
|
||||
List<String> ciphers = new ArrayList<>(Arrays.asList(AbstractSSLService.DEFAULT_CIPHERS));
|
||||
ciphers.add("foo");
|
||||
ciphers.add("bar");
|
||||
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
|
||||
.putArray("shield.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
|
||||
.build());
|
||||
SSLEngine engine = sslService.createSSLEngine();
|
||||
assertThat(engine, is(notNullValue()));
|
||||
String[] enabledCiphers = engine.getEnabledCipherSuites();
|
||||
assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar")));
|
||||
}
|
||||
|
||||
@Test(expected = ShieldSettingsException.class)
|
||||
public void invalidCiphersOnlyThrowsException() throws Exception {
|
||||
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
|
||||
.putArray("shield.ssl.ciphers", new String[] { "foo", "bar" })
|
||||
.build());
|
||||
sslService.createSSLEngine();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ import javax.net.ssl.SSLEngine;
|
|||
import javax.net.ssl.SSLSessionContext;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
@ -161,4 +163,30 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
|
|||
.build());
|
||||
sslService.sslContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validCiphersAndInvalidCiphersWork() throws Exception {
|
||||
List<String> ciphers = new ArrayList<>(Arrays.asList(AbstractSSLService.DEFAULT_CIPHERS));
|
||||
ciphers.add("foo");
|
||||
ciphers.add("bar");
|
||||
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
|
||||
.put("shield.ssl.keystore.path", testnodeStore)
|
||||
.put("shield.ssl.keystore.password", "testnode")
|
||||
.putArray("shield.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
|
||||
.build());
|
||||
SSLEngine engine = sslService.createSSLEngine();
|
||||
assertThat(engine, is(notNullValue()));
|
||||
String[] enabledCiphers = engine.getEnabledCipherSuites();
|
||||
assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar")));
|
||||
}
|
||||
|
||||
@Test(expected = ShieldSettingsException.class)
|
||||
public void invalidCiphersOnlyThrowsException() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
|
||||
.put("shield.ssl.keystore.path", testnodeStore)
|
||||
.put("shield.ssl.keystore.password", "testnode")
|
||||
.putArray("shield.ssl.ciphers", new String[] { "foo", "bar" })
|
||||
.build());
|
||||
sslService.createSSLEngine();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue