You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2018/10/05 15:15:11 UTC

[cxf] 02/04: CXF-7865 - Enable default ciphersuites exclusion filter

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 <co...@apache.org>
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() {