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.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<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 {
Throwable cause = null;
@ -93,7 +116,7 @@ public final class OpenSsl {
UNAVAILABILITY_CAUSE = cause;
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);
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<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 {
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<String> 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<String> availableCipherSuites() {
return AVAILABLE_CIPHER_SUITES;
public static Set<String> 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<String> 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) {

View File

@ -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<String> SUPPORTED_PROTOCOLS_SET = new HashSet<String>(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<String> 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<String> 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;
}
}