OpenSslEngine.getSupportedCipherSuites() must return java names as well.

Motivation:

At the moment OpenSslEngine.getSupportedCipherSuites() only return the original openssl cipher names and not the java names. We need also include the java names.

Modifications:

Correctly return the java names as well.

Result:

Correct implementation of OpenSslEngine.getSupportedCipherSuites()
This commit is contained in:
Norman Maurer 2016-06-22 15:46:45 +02:00
parent 278c36af0c
commit 7c1374dd54
2 changed files with 81 additions and 43 deletions

View File

@ -27,7 +27,9 @@ import org.apache.tomcat.jni.Pool;
import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSL;
import org.apache.tomcat.jni.SSLContext; import org.apache.tomcat.jni.SSLContext;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
@ -43,7 +45,28 @@ public final class OpenSsl {
private static final String UNKNOWN = "unknown"; private static final String UNKNOWN = "unknown";
private static final Throwable UNAVAILABILITY_CAUSE; private static final Throwable UNAVAILABILITY_CAUSE;
private static final Set<String> AVAILABLE_CIPHER_SUITES; static final Set<String> AVAILABLE_CIPHER_SUITES;
private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
private static final Set<String> 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<String> SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(
new HashSet<String>(Arrays.asList(SUPPORTED_PROTOCOLS)));
static { static {
Throwable cause = null; Throwable cause = null;
@ -93,7 +116,7 @@ public final class OpenSsl {
UNAVAILABILITY_CAUSE = cause; UNAVAILABILITY_CAUSE = cause;
if (cause == null) { if (cause == null) {
final Set<String> availableCipherSuites = new LinkedHashSet<String>(128); final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128);
final long aprPool = Pool.create(0); final long aprPool = Pool.create(0);
try { try {
final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER); final long sslCtx = SSLContext.make(aprPool, SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
@ -104,10 +127,10 @@ public final class OpenSsl {
try { try {
for (String c: SSL.getCiphers(ssl)) { for (String c: SSL.getCiphers(ssl)) {
// Filter out bad input. // Filter out bad input.
if (c == null || c.length() == 0 || availableCipherSuites.contains(c)) { if (c == null || c.length() == 0 || availableOpenSslCipherSuites.contains(c)) {
continue; continue;
} }
availableCipherSuites.add(c); availableOpenSslCipherSuites.add(c);
} }
} finally { } finally {
SSL.freeSSL(ssl); SSL.freeSSL(ssl);
@ -120,9 +143,29 @@ public final class OpenSsl {
} finally { } finally {
Pool.destroy(aprPool); Pool.destroy(aprPool);
} }
AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
AVAILABLE_CIPHER_SUITES = Collections.unmodifiableSet(availableCipherSuites); final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>(
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<String> availableCipherSuites = new LinkedHashSet<String>(
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 { } else {
AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
AVAILABLE_CIPHER_SUITES = Collections.emptySet(); AVAILABLE_CIPHER_SUITES = Collections.emptySet();
} }
} }
@ -189,12 +232,28 @@ public final class OpenSsl {
return UNAVAILABILITY_CAUSE; return UNAVAILABILITY_CAUSE;
} }
/**
* @deprecated use {@link #availableOpenSslCipherSuites()}
*/
@Deprecated
public static Set<String> availableCipherSuites() {
return availableOpenSslCipherSuites();
}
/** /**
* Returns all the available OpenSSL cipher suites. * Returns all the available OpenSSL cipher suites.
* Please note that the returned array may include the cipher suites that are insecure or non-functional. * Please note that the returned array may include the cipher suites that are insecure or non-functional.
*/ */
public static Set<String> availableCipherSuites() { public static Set<String> availableOpenSslCipherSuites() {
return AVAILABLE_CIPHER_SUITES; 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<String> availableJavaCipherSuites() {
return AVAILABLE_JAVA_CIPHER_SUITES;
} }
/** /**
@ -206,7 +265,7 @@ public final class OpenSsl {
if (converted != null) { if (converted != null) {
cipherSuite = converted; cipherSuite = converted;
} }
return AVAILABLE_CIPHER_SUITES.contains(cipherSuite); return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
} }
static boolean isError(long errorCode) { static boolean isError(long errorCode) {

View File

@ -37,10 +37,8 @@ import java.security.cert.Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import javax.net.ssl.SSLEngine; 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_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_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<String> SUPPORTED_PROTOCOLS_SET = new HashSet<String>(Arrays.asList(SUPPORTED_PROTOCOLS));
// Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) // 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; static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
@ -1038,8 +1018,7 @@ public final class OpenSslEngine extends SSLEngine {
@Override @Override
public String[] getSupportedCipherSuites() { public String[] getSupportedCipherSuites() {
Set<String> availableCipherSuites = OpenSsl.availableCipherSuites(); return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]);
return availableCipherSuites.toArray(new String[availableCipherSuites.size()]);
} }
@Override @Override
@ -1110,14 +1089,14 @@ public final class OpenSslEngine extends SSLEngine {
@Override @Override
public String[] getSupportedProtocols() { public String[] getSupportedProtocols() {
return SUPPORTED_PROTOCOLS.clone(); return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]);
} }
@Override @Override
public String[] getEnabledProtocols() { public String[] getEnabledProtocols() {
List<String> enabled = InternalThreadLocalMap.get().arrayList(); List<String> enabled = InternalThreadLocalMap.get().arrayList();
// Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled // 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; int opts;
synchronized (this) { synchronized (this) {
@ -1128,19 +1107,19 @@ public final class OpenSslEngine extends SSLEngine {
} }
} }
if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) { 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) { 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) { 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) { 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) { 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()]); return enabled.toArray(new String[enabled.size()]);
} }
@ -1157,18 +1136,18 @@ public final class OpenSslEngine extends SSLEngine {
boolean tlsv1_1 = false; boolean tlsv1_1 = false;
boolean tlsv1_2 = false; boolean tlsv1_2 = false;
for (String p: protocols) { 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."); throw new IllegalArgumentException("Protocol " + p + " is not supported.");
} }
if (p.equals(PROTOCOL_SSL_V2)) { if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) {
sslv2 = true; sslv2 = true;
} else if (p.equals(PROTOCOL_SSL_V3)) { } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) {
sslv3 = true; sslv3 = true;
} else if (p.equals(PROTOCOL_TLS_V1)) { } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) {
tlsv1 = true; tlsv1 = true;
} else if (p.equals(PROTOCOL_TLS_V1_1)) { } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) {
tlsv1_1 = true; tlsv1_1 = true;
} else if (p.equals(PROTOCOL_TLS_V1_2)) { } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) {
tlsv1_2 = true; tlsv1_2 = true;
} }
} }