This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cxf.git
commit e60e8ab5d7414a0dc581c5666873e1ab0413b107 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Fri Oct 5 14:09:59 2018 +0100 CXF-7865 - Enable default ciphersuites exclusion filter --- .../apache/cxf/configuration/jsse/SSLUtils.java | 62 ++++++++++++++-------- .../https/ciphersuites/CipherSuitesTest.java | 54 +++++++++++++++++++ 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java b/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java index de573d8..ed79a51 100644 --- a/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java +++ b/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java @@ -31,12 +31,12 @@ import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; @@ -67,17 +67,12 @@ public final class SSLUtils { private static final String HTTPS_CIPHER_SUITES = "https.cipherSuites"; /** - * By default, exclude NULL, anon, EXPORT, DES, 3DES, MD5, CBC and RC4 ciphersuites + * By default, exclude NULL, anon and EXPORT ciphersuites */ private static final List<String> DEFAULT_CIPHERSUITE_FILTERS_EXCLUDE = - Arrays.asList(new String[] {".*_NULL_.*", - ".*_anon_.*", - ".*_EXPORT_.*", - ".*_DES_.*", - ".*_3DES_.*", - ".*_MD5", - ".*_CBC_.*", - ".*_RC4_.*"}); + Arrays.asList(new String[] {".*NULL.*", + ".*anon.*", + ".*EXPORT.*"}); private static volatile KeyManager[] defaultManagers; @@ -403,16 +398,27 @@ public final class SSLUtils { String[] supportedCipherSuites, Logger log, boolean exclude) { // We have explicit filters, so use the "include/exclude" cipherSuiteFilter configuration + List<Pattern> includes = new ArrayList<>(); + List<Pattern> excludes = new ArrayList<>(); + + if (filters != null) { + // We must have an inclusion pattern specified or no ciphersuites are filtered + compileRegexPatterns(includes, filters.getInclude(), true, log); + + if (filters.isSetExclude()) { + // If we have specified excludes, then the default excludes are ignored + compileRegexPatterns(excludes, filters.getExclude(), false, log); + } else { + // Otherwise use the default excludes, but remove from the default excludes any + // ciphersuites explicitly matched by the inclusion filters + List<String> filteredExcludes = + filterDefaultExcludes(filters.getInclude(), DEFAULT_CIPHERSUITE_FILTERS_EXCLUDE); + compileRegexPatterns(excludes, filteredExcludes, false, log); + } + } + List<String> filteredCipherSuites = new ArrayList<>(); List<String> excludedCipherSuites = new ArrayList<>(); - List<Pattern> includes = - filters != null - ? compileRegexPatterns(filters.getInclude(), true, log) - : Collections.emptyList(); - List<Pattern> excludes = - filters != null - ? compileRegexPatterns(filters.getExclude(), false, log) - : compileRegexPatterns(DEFAULT_CIPHERSUITE_FILTERS_EXCLUDE, true, log); for (int i = 0; i < supportedCipherSuites.length; i++) { if (matchesOneOf(supportedCipherSuites[i], includes) && !matchesOneOf(supportedCipherSuites[i], excludes)) { @@ -443,6 +449,19 @@ public final class SSLUtils { return getCiphersFromList(filteredCipherSuites, log, exclude); } + private static List<String> filterDefaultExcludes(List<String> includes, List<String> defaultExcludes) { + if (includes != null && !includes.isEmpty()) { + // Filter the default exclusion filters to remove any that explicitly match the inclusion filters + // e.g. if the user wants the NULL ciphersuite then remove it from the default excludes + return defaultExcludes.stream() + .filter(ex -> !includes.stream() + .anyMatch(inc -> inc.matches(ex))) + .collect(Collectors.toList()); + } + + return defaultExcludes; + } + private static String[] getSystemCiphersuites(Logger log) { String jvmCipherSuites = System.getProperty(HTTPS_CIPHER_SUITES); if ((jvmCipherSuites != null) && (!jvmCipherSuites.isEmpty())) { @@ -453,10 +472,8 @@ public final class SSLUtils { } - private static List<Pattern> compileRegexPatterns(List<String> regexes, - boolean include, - Logger log) { - List<Pattern> patterns = new ArrayList<>(); + private static void compileRegexPatterns(List<Pattern> patterns, List<String> regexes, + boolean include, Logger log) { if (regexes != null) { String msg = include ? "CIPHERSUITE_INCLUDE_FILTER" @@ -466,7 +483,6 @@ public final class SSLUtils { patterns.add(Pattern.compile(s)); } } - return patterns; } private static boolean matchesOneOf(String s, List<Pattern> patterns) { diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/https/ciphersuites/CipherSuitesTest.java b/systests/transports/src/test/java/org/apache/cxf/systest/https/ciphersuites/CipherSuitesTest.java index 9503101..7a4c54b 100644 --- a/systests/transports/src/test/java/org/apache/cxf/systest/https/ciphersuites/CipherSuitesTest.java +++ b/systests/transports/src/test/java/org/apache/cxf/systest/https/ciphersuites/CipherSuitesTest.java @@ -22,11 +22,13 @@ package org.apache.cxf.systest.https.ciphersuites; import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Arrays; import java.util.Collections; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.xml.ws.BindingProvider; @@ -34,7 +36,10 @@ import javax.xml.ws.BindingProvider; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.bus.spring.SpringBusFactory; +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.configuration.jsse.SSLUtils; import org.apache.cxf.configuration.jsse.TLSClientParameters; +import org.apache.cxf.configuration.security.FiltersType; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.helpers.JavaUtils; @@ -670,6 +675,55 @@ public class CipherSuitesTest extends AbstractBusClientServerTestBase { bus.shutdown(true); } + @org.junit.Test + public void testDefaultCipherSuitesFilterExcluded() throws Exception { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, new java.security.SecureRandom()); + + FiltersType filtersType = new FiltersType(); + filtersType.getInclude().add(".*_AES_.*"); + String[] supportedCipherSuites = sslContext.getSocketFactory().getSupportedCipherSuites(); + String[] filteredCipherSuites = SSLUtils.getFilteredCiphersuites(filtersType, supportedCipherSuites, + LogUtils.getL7dLogger(CipherSuitesTest.class), false); + + // Check we have no anon/EXPORT/NULL/etc ciphersuites + assertFalse(Arrays.stream( + filteredCipherSuites).anyMatch(c -> c.matches(".*NULL|anon|EXPORT.*"))); + } + + @org.junit.Test + public void testExclusionFilter() throws Exception { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, new java.security.SecureRandom()); + + FiltersType filtersType = new FiltersType(); + filtersType.getInclude().add(".*_AES_.*"); + filtersType.getExclude().add(".*anon.*"); + String[] supportedCipherSuites = sslContext.getSocketFactory().getSupportedCipherSuites(); + String[] filteredCipherSuites = SSLUtils.getFilteredCiphersuites(filtersType, supportedCipherSuites, + LogUtils.getL7dLogger(CipherSuitesTest.class), false); + + // Check we have no anon ciphersuites + assertFalse(Arrays.stream( + filteredCipherSuites).anyMatch(c -> c.matches(".*anon.*"))); + } + + @org.junit.Test + public void testInclusionFilter() throws Exception { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, new java.security.SecureRandom()); + + FiltersType filtersType = new FiltersType(); + filtersType.getInclude().add(".*anon.*"); + String[] supportedCipherSuites = sslContext.getSocketFactory().getSupportedCipherSuites(); + String[] filteredCipherSuites = SSLUtils.getFilteredCiphersuites(filtersType, supportedCipherSuites, + LogUtils.getL7dLogger(CipherSuitesTest.class), false); + + // Check we have anon ciphersuites + assertTrue(Arrays.stream( + filteredCipherSuites).anyMatch(c -> c.matches(".*anon.*"))); + } + private static class NoOpX509TrustManager implements X509TrustManager { NoOpX509TrustManager() {
