From 8774e9a000c4b5ae545f2dad7a5f5d94d360b2b1 Mon Sep 17 00:00:00 2001 From: Mark Thomas Date: Mon, 10 Aug 2015 19:52:17 +0000 Subject: [PATCH] OpenSSL cipher mapping in trunk now works (i.e. tests pass) with 1.0.2. Need to test with 1.1.0 - I suspect some 'tweaks' will be required. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1695159 13f79535-47bb-0310-9956-ffa450edef68 --- .../tomcat/util/net/jsse/openssl/Cipher.java | 2 +- .../OpenSSLCipherConfigurationParser.java | 3 +- .../util/net/jsse/openssl/TestCipher.java | 44 +--- .../TestOpenSSLCipherConfigurationParser.java | 8 - .../util/net/jsse/openssl/TesterOpenSSL.java | 210 +++++++++++++++--- 5 files changed, 186 insertions(+), 81 deletions(-) diff --git a/java/org/apache/tomcat/util/net/jsse/openssl/Cipher.java b/java/org/apache/tomcat/util/net/jsse/openssl/Cipher.java index 724d093a5d0..0918b60669b 100644 --- a/java/org/apache/tomcat/util/net/jsse/openssl/Cipher.java +++ b/java/org/apache/tomcat/util/net/jsse/openssl/Cipher.java @@ -4021,7 +4021,7 @@ public enum Cipher { // RC2_128_CBC_WITH_MD5 SSL_CK_RC2_128_CBC_WITH_MD5( -1, - "RC2-MD5", + "RC2-CBC-MD5", KeyExchange.RSA, Authentication.RSA, Encryption.RC2, diff --git a/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java b/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java index 7431fb41a67..676ea9e8d2d 100644 --- a/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java +++ b/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java @@ -485,12 +485,13 @@ private static final void init() { addListAlias(SRP, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.SRP))); initialized = true; // Despite what the OpenSSL docs say, DEFAULT also excludes SSLv2 - addListAlias(DEFAULT, parse("ALL:!eNULL:!aNULL:!SSLv2")); + addListAlias(DEFAULT, parse("ALL:!EXPORT:!eNULL:!aNULL:!SSLv2")); // COMPLEMENTOFDEFAULT is also not exactly as defined by the docs Set complementOfDefault = filterByKeyExchange(all, new HashSet<>(Arrays.asList(KeyExchange.EDH,KeyExchange.EECDH))); complementOfDefault = filterByAuthentication(complementOfDefault, Collections.singleton(Authentication.aNULL)); complementOfDefault.removeAll(aliases.get(eNULL)); complementOfDefault.addAll(aliases.get(Constants.SSL_PROTO_SSLv2)); + complementOfDefault.addAll(aliases.get(EXPORT)); addListAlias(COMPLEMENTOFDEFAULT, complementOfDefault); } diff --git a/test/org/apache/tomcat/util/net/jsse/openssl/TestCipher.java b/test/org/apache/tomcat/util/net/jsse/openssl/TestCipher.java index f9bdc504569..393458b2ab6 100644 --- a/test/org/apache/tomcat/util/net/jsse/openssl/TestCipher.java +++ b/test/org/apache/tomcat/util/net/jsse/openssl/TestCipher.java @@ -23,17 +23,10 @@ import java.util.Set; import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; import org.junit.Test; public class TestCipher { - @Before - public void checkVersion() { - Assume.assumeTrue(TesterOpenSSL.IS_EXPECTED_VERSION); - } - /* * Checks that every cipher suite returned by OpenSSL is mapped to at least * one cipher suite that is recognised by JSSE or is a cipher suite known @@ -83,43 +76,10 @@ public void testOpenSSLCipherAvailability() throws Exception { Set availableCipherSuites = TesterOpenSSL.getOpenSSLCiphersAsSet("ALL:eNULL"); Set expectedCipherSuites = new HashSet<>(); for (Cipher cipher : Cipher.values()) { - String openSSLAlias = cipher.getOpenSSLAlias(); - // OpenSSL does not implement any FORTEZZA algorithms so exclude - // them from the expected list - if (openSSLAlias.contains("FZA")) { - continue; - } - // GOST algorithms are not enabled by default and no JSSE - // implementation supports them so exclude them from the expected - // list - if (openSSLAlias.contains("GOST")) { - continue; - } - // OpenSSL does not enable the experimental EXP1024 and - // DHE-DSS-RC4-SHA cipher suites unless the source is explicitly - // patched so exclude them from the expected list - if (openSSLAlias.contains("EXP1024")) { - continue; - } - if (openSSLAlias.contains("DHE-DSS-RC4-SHA")) { - continue; - } - // OpenSSL removed (broken) support for EXP-DH-RSA-DES-CBC-SHA - // and EXP-DH-DSS-DES-CBC-SHA on 2015-05-23. - if (openSSLAlias.contains("EXP-DH-")) { - continue; - } - // RC2-MD5 is not referenced in the OpenSSL source so exclude it - // from the expected list - if (openSSLAlias.contains("RC2-MD5")) { - continue; - } - // As of OpenSSL 1.1.0, SSLv2 ciphers are not supported so exclude - // them from the expected list - if (cipher.getProtocol().equals(Protocol.SSLv2)) { + if (TesterOpenSSL.OPENSSL_UNIMPLEMENTED_CIPHERS.contains(cipher)) { continue; } - expectedCipherSuites.add(openSSLAlias + "+" + + expectedCipherSuites.add(cipher.getOpenSSLAlias() + "+" + cipher.getProtocol().getOpenSSLName()); } diff --git a/test/org/apache/tomcat/util/net/jsse/openssl/TestOpenSSLCipherConfigurationParser.java b/test/org/apache/tomcat/util/net/jsse/openssl/TestOpenSSLCipherConfigurationParser.java index 2276f9cbd21..a35a3535665 100644 --- a/test/org/apache/tomcat/util/net/jsse/openssl/TestOpenSSLCipherConfigurationParser.java +++ b/test/org/apache/tomcat/util/net/jsse/openssl/TestOpenSSLCipherConfigurationParser.java @@ -19,19 +19,11 @@ import java.util.List; import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; import org.junit.Ignore; import org.junit.Test; public class TestOpenSSLCipherConfigurationParser { - @Before - public void checkVersion() { - Assume.assumeTrue(TesterOpenSSL.IS_EXPECTED_VERSION); - } - - @Test public void testDEFAULT() throws Exception { testSpecification("DEFAULT"); diff --git a/test/org/apache/tomcat/util/net/jsse/openssl/TesterOpenSSL.java b/test/org/apache/tomcat/util/net/jsse/openssl/TesterOpenSSL.java index a9bcb383f53..3646bc099ef 100644 --- a/test/org/apache/tomcat/util/net/jsse/openssl/TesterOpenSSL.java +++ b/test/org/apache/tomcat/util/net/jsse/openssl/TesterOpenSSL.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -30,45 +29,196 @@ public class TesterOpenSSL { - public static final boolean IS_EXPECTED_VERSION; - - public static final Set OPENSSL_UNIMPLEMENTED_CIPHERS = - Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - // The following ciphers are not implemented in an OpenSSL - // version - Cipher.SSL2_DES_64_CBC_WITH_MD5, - Cipher.SSL_CK_RC2_128_CBC_WITH_MD5, - // The following are not implemented in 1.1.x onwards. They - // are implemented in 1.0.x and earlier - Cipher.SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, - Cipher.SSL_CK_RC4_128_WITH_MD5, - Cipher.SSL2_DES_64_CBC_WITH_MD5, - Cipher.SSL2_DES_192_EDE3_CBC_WITH_MD5, - Cipher.SSL2_IDEA_128_CBC_WITH_MD5, - Cipher.SSL2_RC4_128_EXPORT40_WITH_MD5, - Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_MD5, - Cipher.TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, - Cipher.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, - Cipher.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, - Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - Cipher.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, - Cipher.TLS_DHE_DSS_WITH_RC4_128_SHA, - // The following have been removed from OpenSSL on 2015-05-23 - Cipher.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, - Cipher.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA))); + public static final int VERSION; + + public static final Set OPENSSL_UNIMPLEMENTED_CIPHERS; static { // Note: The tests are configured for the OpenSSL 1.1.0 development // branch. Running with a different version is likely to trigger // failures. - String expected_version = System.getProperty("tomcat.test.openssl.version", ""); String versionString = null; try { versionString = executeOpenSSLCommand("version"); } catch (IOException e) { versionString = ""; } - IS_EXPECTED_VERSION = versionString.startsWith("OpenSSL " + expected_version); + if (versionString.startsWith("OpenSSL 1.1.0")) { + VERSION = 10100; + } else if (versionString.startsWith("OpenSSL 1.0.2")) { + VERSION = 10002; + } else if (versionString.startsWith("OpenSSL 1.0.1")) { + VERSION = 10001; + } else if (versionString.startsWith("OpenSSL 1.0.0")) { + VERSION = 10000; + } else if (versionString.startsWith("OpenSSL 0.9.8")) { + VERSION = 908; + } else { + // Unknown OpenSSL version + throw new IllegalStateException("Unknown OpenSSL version " + versionString); + } + + HashSet unimplemented = new HashSet<>(); + + // Note: The following lists are intended to be aligned with the most + // recent release of each OpenSSL release branch + + // TODO Validate this for all OpenSSL versions + // 0.9.8 - TODO + // 1.0.0 - TODO + // 1.0.1 - TODO + // 1.0.2 - Done + // 1.1.0 - TODO + + // These were removed in 0.9.8 (or earlier) so won't be available in any + // supported version. + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_RC4_128_SHA); + unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5); + unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_MD5); + + if (VERSION < 10000) { + // These were implemented in 1.0.0 so won't be available in any + // earlier version + } else { + // These were removed in 1.0.0 so won't be available from that + // version onwards. + } + + + if (VERSION < 10001) { + // These were added in 1.0.1 so won't be available in any earlier + // version + unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_GCM_SHA256); + unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_GCM_SHA384); + } else { + // These were removed in 1.0.1 so won't be available from that + // version onwards. + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_MD5); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA); + unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA); + unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA); + unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA); + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_RC4_128_SHA); + } + + if (VERSION < 10002) { + // These were implemented in 1.0.2 so won't be available in any + // earlier version + } else { + // These were removed in 1.0.2 so won't be available from that + // version onwards. + unimplemented.add(Cipher.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); + unimplemented.add(Cipher.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); + } + + if (VERSION < 10100) { + // These were implemented in 1.1.0 so won't be available in any + // earlier version + unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384); + unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA256); + unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA384); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA256); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA384); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA256); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA384); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA384); + unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384); + unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256); + unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256); + unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_GCM_SHA256); + unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_GCM_SHA384); + unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256); + } else { + // These were removed in 1.1.0 so won't be available from that + // version onwards. + unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5); + unimplemented.add(Cipher.SSL_CK_RC4_128_WITH_MD5); + unimplemented.add(Cipher.SSL2_DES_192_EDE3_CBC_WITH_MD5); + unimplemented.add(Cipher.SSL2_DES_64_CBC_WITH_MD5); + unimplemented.add(Cipher.SSL2_IDEA_128_CBC_WITH_MD5); + unimplemented.add(Cipher.SSL2_RC4_128_EXPORT40_WITH_MD5); + unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_WITH_MD5); + } + OPENSSL_UNIMPLEMENTED_CIPHERS = Collections.unmodifiableSet(unimplemented); } @@ -106,6 +256,8 @@ public static String getOpenSSLCiphersAsExpression(String specification) throws // OpenSSL should have returned one cipher per line String ciphers[] = stdout.split("\n"); for (String cipher : ciphers) { + // Handle rename for 1.1.0 onwards + cipher = cipher.replaceAll("EDH", "DHE"); if (first) { first = false; } else {