Raise an exception when the specified cipher suite is not available
Motivation: SSL_set_cipher_list() in OpenSSL does not fail as long as at least one cipher suite is available. It is different from the semantics of SSLEngine.setEnabledCipherSuites(), which raises an exception when the list contains an unavailable cipher suite. Modifications: - Add OpenSsl.isCipherSuiteAvailable(String) which checks the availability of a cipher suite - Raise an IllegalArgumentException when the specified cipher suite is not available Result: Fixed compatibility
This commit is contained in:
parent
7d50f7864c
commit
ea5f38955a
@ -24,9 +24,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.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
|
* Tells if <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
|
||||||
@ -37,7 +37,7 @@ public final class OpenSsl {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
|
||||||
private static final Throwable UNAVAILABILITY_CAUSE;
|
private static final Throwable UNAVAILABILITY_CAUSE;
|
||||||
|
|
||||||
private static final List<String> AVAILABLE_CIPHER_SUITES;
|
private static final Set<String> AVAILABLE_CIPHER_SUITES;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
@ -54,7 +54,7 @@ public final class OpenSsl {
|
|||||||
UNAVAILABILITY_CAUSE = cause;
|
UNAVAILABILITY_CAUSE = cause;
|
||||||
|
|
||||||
if (cause == null) {
|
if (cause == null) {
|
||||||
final List<String> availableCipherSuites = new ArrayList<String>(128);
|
final Set<String> availableCipherSuites = 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);
|
||||||
@ -82,9 +82,9 @@ public final class OpenSsl {
|
|||||||
Pool.destroy(aprPool);
|
Pool.destroy(aprPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
AVAILABLE_CIPHER_SUITES = Collections.unmodifiableList(availableCipherSuites);
|
AVAILABLE_CIPHER_SUITES = Collections.unmodifiableSet(availableCipherSuites);
|
||||||
} else {
|
} else {
|
||||||
AVAILABLE_CIPHER_SUITES = Collections.emptyList();
|
AVAILABLE_CIPHER_SUITES = Collections.emptySet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +124,20 @@ public final class OpenSsl {
|
|||||||
* 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 String[] availableCipherSuites() {
|
public static Set<String> availableCipherSuites() {
|
||||||
return AVAILABLE_CIPHER_SUITES.toArray(new String[AVAILABLE_CIPHER_SUITES.size()]);
|
return AVAILABLE_CIPHER_SUITES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
|
||||||
|
* Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
|
||||||
|
*/
|
||||||
|
public static boolean isCipherSuiteAvailable(String cipherSuite) {
|
||||||
|
String converted = CipherSuiteConverter.toOpenSsl(cipherSuite);
|
||||||
|
if (converted != null) {
|
||||||
|
cipherSuite = converted;
|
||||||
|
}
|
||||||
|
return AVAILABLE_CIPHER_SUITES.contains(cipherSuite);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isError(long errorCode) {
|
static boolean isError(long errorCode) {
|
||||||
|
@ -650,7 +650,8 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getSupportedCipherSuites() {
|
public String[] getSupportedCipherSuites() {
|
||||||
return OpenSsl.availableCipherSuites();
|
Set<String> availableCipherSuites = OpenSsl.availableCipherSuites();
|
||||||
|
return availableCipherSuites.toArray(new String[availableCipherSuites.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -677,11 +678,35 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
throw new NullPointerException("cipherSuites");
|
throw new NullPointerException("cipherSuites");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String converted = CipherSuiteConverter.toOpenSsl(Arrays.asList(cipherSuites));
|
final StringBuilder buf = new StringBuilder();
|
||||||
|
for (String c: cipherSuites) {
|
||||||
|
if (c == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String converted = CipherSuiteConverter.toOpenSsl(c);
|
||||||
|
if (converted == null) {
|
||||||
|
converted = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!OpenSsl.isCipherSuiteAvailable(converted)) {
|
||||||
|
throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.append(converted);
|
||||||
|
buf.append(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.length() == 0) {
|
||||||
|
throw new IllegalArgumentException("empty cipher suites");
|
||||||
|
}
|
||||||
|
buf.setLength(buf.length() - 1);
|
||||||
|
|
||||||
|
final String cipherSuiteSpec = buf.toString();
|
||||||
try {
|
try {
|
||||||
SSL.setCipherSuites(ssl, converted);
|
SSL.setCipherSuites(ssl, cipherSuiteSpec);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException("failed to enable cipher suites: " + converted, e);
|
throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user