diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java index 92ea5b8603..f345de16b5 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java @@ -27,7 +27,9 @@ import org.apache.tomcat.jni.Pool; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; @@ -43,7 +45,28 @@ public final class OpenSsl { private static final String UNKNOWN = "unknown"; private static final Throwable UNAVAILABILITY_CAUSE; - private static final Set AVAILABLE_CIPHER_SUITES; + static final Set AVAILABLE_CIPHER_SUITES; + private static final Set AVAILABLE_OPENSSL_CIPHER_SUITES; + private static final Set AVAILABLE_JAVA_CIPHER_SUITES; + + // Protocols + static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello"; + static final String PROTOCOL_SSL_V2 = "SSLv2"; + static final String PROTOCOL_SSL_V3 = "SSLv3"; + static final String PROTOCOL_TLS_V1 = "TLSv1"; + static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; + static final String PROTOCOL_TLS_V1_2 = "TLSv1.2"; + + private static final String[] SUPPORTED_PROTOCOLS = { + PROTOCOL_SSL_V2_HELLO, + PROTOCOL_SSL_V2, + PROTOCOL_SSL_V3, + PROTOCOL_TLS_V1, + PROTOCOL_TLS_V1_1, + PROTOCOL_TLS_V1_2 + }; + static final Set SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet( + new HashSet(Arrays.asList(SUPPORTED_PROTOCOLS))); static { Throwable cause = null; @@ -93,7 +116,7 @@ public final class OpenSsl { UNAVAILABILITY_CAUSE = cause; if (cause == null) { - final Set availableCipherSuites = new LinkedHashSet(128); + final Set availableOpenSslCipherSuites = new LinkedHashSet(128); final long aprPool = Pool.create(0); try { final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); @@ -104,10 +127,10 @@ public final class OpenSsl { try { for (String c: SSL.getCiphers(ssl)) { // Filter out bad input. - if (c == null || c.length() == 0 || availableCipherSuites.contains(c)) { + if (c == null || c.length() == 0 || availableOpenSslCipherSuites.contains(c)) { continue; } - availableCipherSuites.add(c); + availableOpenSslCipherSuites.add(c); } } finally { SSL.freeSSL(ssl); @@ -120,9 +143,29 @@ public final class OpenSsl { } finally { Pool.destroy(aprPool); } + AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites); - AVAILABLE_CIPHER_SUITES = Collections.unmodifiableSet(availableCipherSuites); + final Set availableJavaCipherSuites = new LinkedHashSet( + AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2); + for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { + // Included converted but also openssl cipher name + availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS")); + availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL")); + } + AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites); + + final Set availableCipherSuites = new LinkedHashSet( + AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size()); + for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) { + availableCipherSuites.add(cipher); + } + for (String cipher: AVAILABLE_JAVA_CIPHER_SUITES) { + availableCipherSuites.add(cipher); + } + AVAILABLE_CIPHER_SUITES = availableCipherSuites; } else { + AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet(); + AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet(); AVAILABLE_CIPHER_SUITES = Collections.emptySet(); } } @@ -189,12 +232,28 @@ public final class OpenSsl { return UNAVAILABILITY_CAUSE; } + /** + * @deprecated use {@link #availableOpenSslCipherSuites()} + */ + @Deprecated + public static Set availableCipherSuites() { + return availableOpenSslCipherSuites(); + } + /** * Returns all the available OpenSSL cipher suites. * Please note that the returned array may include the cipher suites that are insecure or non-functional. */ - public static Set availableCipherSuites() { - return AVAILABLE_CIPHER_SUITES; + public static Set availableOpenSslCipherSuites() { + return AVAILABLE_OPENSSL_CIPHER_SUITES; + } + + /** + * Returns all the available cipher suites (Java-style). + * Please note that the returned array may include the cipher suites that are insecure or non-functional. + */ + public static Set availableJavaCipherSuites() { + return AVAILABLE_JAVA_CIPHER_SUITES; } /** @@ -206,7 +265,7 @@ public final class OpenSsl { if (converted != null) { cipherSuite = converted; } - return AVAILABLE_CIPHER_SUITES.contains(cipherSuite); + return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite); } static boolean isError(long errorCode) { diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java index f47693d4b0..d83171837a 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java @@ -37,10 +37,8 @@ import java.security.cert.Certificate; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import javax.net.ssl.SSLEngine; @@ -154,24 +152,6 @@ public final class OpenSslEngine extends SSLEngine { private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024; private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024; - // Protocols - private static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello"; - private static final String PROTOCOL_SSL_V2 = "SSLv2"; - private static final String PROTOCOL_SSL_V3 = "SSLv3"; - private static final String PROTOCOL_TLS_V1 = "TLSv1"; - private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; - private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2"; - - private static final String[] SUPPORTED_PROTOCOLS = { - PROTOCOL_SSL_V2_HELLO, - PROTOCOL_SSL_V2, - PROTOCOL_SSL_V3, - PROTOCOL_TLS_V1, - PROTOCOL_TLS_V1_1, - PROTOCOL_TLS_V1_2 - }; - private static final Set SUPPORTED_PROTOCOLS_SET = new HashSet(Arrays.asList(SUPPORTED_PROTOCOLS)); - // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256; @@ -1038,8 +1018,7 @@ public final class OpenSslEngine extends SSLEngine { @Override public String[] getSupportedCipherSuites() { - Set availableCipherSuites = OpenSsl.availableCipherSuites(); - return availableCipherSuites.toArray(new String[availableCipherSuites.size()]); + return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]); } @Override @@ -1110,14 +1089,14 @@ public final class OpenSslEngine extends SSLEngine { @Override public String[] getSupportedProtocols() { - return SUPPORTED_PROTOCOLS.clone(); + return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]); } @Override public String[] getEnabledProtocols() { List enabled = InternalThreadLocalMap.get().arrayList(); // Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled - enabled.add(PROTOCOL_SSL_V2_HELLO); + enabled.add(OpenSsl.PROTOCOL_SSL_V2_HELLO); int opts; synchronized (this) { @@ -1128,19 +1107,19 @@ public final class OpenSslEngine extends SSLEngine { } } if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) { - enabled.add(PROTOCOL_TLS_V1); + enabled.add(OpenSsl.PROTOCOL_TLS_V1); } if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) { - enabled.add(PROTOCOL_TLS_V1_1); + enabled.add(OpenSsl.PROTOCOL_TLS_V1_1); } if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) { - enabled.add(PROTOCOL_TLS_V1_2); + enabled.add(OpenSsl.PROTOCOL_TLS_V1_2); } if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) { - enabled.add(PROTOCOL_SSL_V2); + enabled.add(OpenSsl.PROTOCOL_SSL_V2); } if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) { - enabled.add(PROTOCOL_SSL_V3); + enabled.add(OpenSsl.PROTOCOL_SSL_V3); } return enabled.toArray(new String[enabled.size()]); } @@ -1157,18 +1136,18 @@ public final class OpenSslEngine extends SSLEngine { boolean tlsv1_1 = false; boolean tlsv1_2 = false; for (String p: protocols) { - if (!SUPPORTED_PROTOCOLS_SET.contains(p)) { + if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) { throw new IllegalArgumentException("Protocol " + p + " is not supported."); } - if (p.equals(PROTOCOL_SSL_V2)) { + if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) { sslv2 = true; - } else if (p.equals(PROTOCOL_SSL_V3)) { + } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) { sslv3 = true; - } else if (p.equals(PROTOCOL_TLS_V1)) { + } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) { tlsv1 = true; - } else if (p.equals(PROTOCOL_TLS_V1_1)) { + } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) { tlsv1_1 = true; - } else if (p.equals(PROTOCOL_TLS_V1_2)) { + } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) { tlsv1_2 = true; } }