diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java index 5df971c46d0..df879fe9e82 100644 --- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java +++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java @@ -91,6 +91,8 @@ public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFa SSLParameters sslparams = c.getDefaultSSLParameters(); params.setSSLParameters(sslparams); + params.setProtocols(SSLUtils.getRecommendedProtocols()); + params.setCipherSuites(SSLUtils.getRecommendedCiphers()); // statement above could throw IAE if any params invalid. // eg. if app has a UI and parameters supplied by a user. } @@ -110,7 +112,8 @@ public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFa SSLServerSocket srvSock = null; SSLServerSocketFactory ssf = sslContext.getServerSocketFactory(); srvSock = (SSLServerSocket)ssf.createServerSocket(port); - srvSock.setEnabledProtocols(SSLUtils.getSupportedProtocols(srvSock.getEnabledProtocols())); + srvSock.setEnabledProtocols(SSLUtils.getRecommendedProtocols()); + srvSock.setEnabledCipherSuites(SSLUtils.getRecommendedCiphers()); s_logger.info("create SSL server socket on port: " + port); return srvSock; diff --git a/systemvm/scripts/_run.sh b/systemvm/scripts/_run.sh index 3792261c143..6d77002b8c4 100755 --- a/systemvm/scripts/_run.sh +++ b/systemvm/scripts/_run.sh @@ -68,4 +68,4 @@ if [ "$(uname -m | grep '64')" == "" ]; then fi fi -java -Djavax.net.ssl.trustStore=./certs/realhostip.keystore -Djsse.enableSNIExtension=false -Dlog.home=$LOGHOME -mx${maxmem}m -cp $CP com.cloud.agent.AgentShell $keyvalues $@ +java -Djavax.net.ssl.trustStore=./certs/realhostip.keystore -Djdk.tls.ephemeralDHKeySize=2048 -Djsse.enableSNIExtension=false -Dlog.home=$LOGHOME -mx${maxmem}m -cp $CP com.cloud.agent.AgentShell $keyvalues $@ diff --git a/utils/src/main/java/org/apache/cloudstack/utils/security/SSLUtils.java b/utils/src/main/java/org/apache/cloudstack/utils/security/SSLUtils.java index c1fc2d606f2..8016f5a1916 100644 --- a/utils/src/main/java/org/apache/cloudstack/utils/security/SSLUtils.java +++ b/utils/src/main/java/org/apache/cloudstack/utils/security/SSLUtils.java @@ -39,7 +39,24 @@ public class SSLUtils { } set.add(s); } - return (String[]) set.toArray(new String[set.size()]); + return set.toArray(new String[set.size()]); + } + + /** + * It returns recommended protocols that are considered secure. + */ + public static String[] getRecommendedProtocols() { + return new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" }; + } + + /** + * It returns recommended ciphers that are considered secure. + */ + public static String[] getRecommendedCiphers() { + return new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" }; } public static String[] getSupportedCiphers() throws NoSuchAlgorithmException { @@ -49,10 +66,10 @@ public class SSLUtils { } public static SSLContext getSSLContext() throws NoSuchAlgorithmException { - return SSLContext.getInstance("TLSv1"); + return SSLContext.getInstance("TLSv1.2"); } public static SSLContext getSSLContext(String provider) throws NoSuchAlgorithmException, NoSuchProviderException { - return SSLContext.getInstance("TLSv1", provider); + return SSLContext.getInstance("TLSv1.2", provider); } } diff --git a/utils/src/test/java/com/cloud/utils/security/SSLUtilsTest.java b/utils/src/test/java/com/cloud/utils/security/SSLUtilsTest.java new file mode 100644 index 00000000000..625b538d7f2 --- /dev/null +++ b/utils/src/test/java/com/cloud/utils/security/SSLUtilsTest.java @@ -0,0 +1,79 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.cloud.utils.security; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.util.ArrayList; +import java.util.Arrays; + +import org.apache.cloudstack.utils.security.SSLUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SSLUtilsTest { + + @Spy + private SSLUtils spySSLUtils; + + @Test + public void getRecommendedProtocolsTest() { + ArrayList protocolsList = new ArrayList<>(Arrays.asList(spySSLUtils.getRecommendedProtocols())); + verifyProtocols(protocolsList); + } + + @Test + public void getRecommendedCiphers() { + String[] expectedCiphers = { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" }; + Assert.assertArrayEquals(expectedCiphers, spySSLUtils.getRecommendedCiphers()); + } + + @Test + public void getSSLContextTest() throws NoSuchAlgorithmException { + Assert.assertEquals("TLSv1.2", spySSLUtils.getSSLContext().getProtocol()); + } + + @Test + public void getSSLContextTestStringAsParameter() throws NoSuchAlgorithmException, NoSuchProviderException { + Assert.assertEquals("TLSv1.2", spySSLUtils.getSSLContext("SunJSSE").getProtocol()); + } + + @Test + public void getSupportedProtocolsTest() { + ArrayList protocolsList = new ArrayList<>(Arrays.asList(spySSLUtils.getSupportedProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "SSLv3", "SSLv2Hello" }))); + verifyProtocols(protocolsList); + } + + private void verifyProtocols(ArrayList protocolsList) { + Assert.assertTrue(protocolsList.contains("TLSv1")); + Assert.assertTrue(protocolsList.contains("TLSv1.1")); + Assert.assertTrue(protocolsList.contains("TLSv1.2")); + Assert.assertFalse(protocolsList.contains("SSLv3")); + Assert.assertFalse(protocolsList.contains("SSLv2Hello")); + } + +}