Cipher suite conversion between Java and OpenSSL
Related: #3285 Motivation: When a user attempts to switch from JdkSslContext to OpenSslContext, he or she will see the initialization failure if he or she specified custom cipher suites. Modifications: - Provide a utility class that converts between Java cipher suite string and OpenSSL cipher suite string - Attempt to convert the cipher suite so that a user can use the cipher suite string format of Java regardless of the chosen SslContext impl Result: - It is possible to convert all known cipher suite strings. - It is possible to switch from JdkSslContext and OpenSslContext and vice versa without any configuration changes
This commit is contained in:
parent
155c0e2f36
commit
a093f00b67
@ -0,0 +1,503 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
|
import io.netty.util.internal.EmptyArrays;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Java cipher suite string to an OpenSSL cipher suite string and vice versa.
|
||||||
|
*
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/Cipher_suite">Wikipedia page about cipher suite</a>
|
||||||
|
*/
|
||||||
|
final class CipherSuiteConverter {
|
||||||
|
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverter.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A_B_WITH_C_D, where:
|
||||||
|
*
|
||||||
|
* A - TLS or SSL (protocol)
|
||||||
|
* B - handshake algorithm (key exchange and authentication algorithms to be precise)
|
||||||
|
* C - bulk cipher
|
||||||
|
* D - HMAC algorithm
|
||||||
|
*
|
||||||
|
* This regular expression assumees that:
|
||||||
|
*
|
||||||
|
* 1) A is always TLS or SSL, and
|
||||||
|
* 2) D is always a single word.
|
||||||
|
*/
|
||||||
|
private static final Pattern JAVA_CIPHERSUITE_PATTERN =
|
||||||
|
Pattern.compile("^(?:TLS|SSL)_((?:(?!_WITH_).)+)_WITH_(.*)_(.*)$");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A-B-C, where:
|
||||||
|
*
|
||||||
|
* A - handshake algorithm (key exchange and authentication algorithms to be precise)
|
||||||
|
* B - bulk cipher
|
||||||
|
* C - HMAC algorithm
|
||||||
|
*
|
||||||
|
* This regular expression assumes that:
|
||||||
|
*
|
||||||
|
* 1) A has some deterministic pattern as shown below, and
|
||||||
|
* 2) C is always a single word
|
||||||
|
*/
|
||||||
|
private static final Pattern OPENSSL_CIPHERSUITE_PATTERN =
|
||||||
|
// Be very careful not to break the indentation while editing.
|
||||||
|
Pattern.compile(
|
||||||
|
"^(?:(" + // BEGIN handshake algorithm
|
||||||
|
"(?:(?:EXP-)?" +
|
||||||
|
"(?:" +
|
||||||
|
"(?:DHE|EDH|ECDH|ECDHE)-(?:DSS|RSA|ECDSA)|" +
|
||||||
|
"(?:ADH|AECDH|KRB5|PSK)" +
|
||||||
|
')' +
|
||||||
|
")|" +
|
||||||
|
"EXP" +
|
||||||
|
")-)?" + // END handshake algorithm
|
||||||
|
"(.*)-(.*)$");
|
||||||
|
|
||||||
|
private static final Pattern JAVA_AES_CBC_PATTERN = Pattern.compile("^(AES)_([0-9]+)_CBC$");
|
||||||
|
private static final Pattern JAVA_AES_PATTERN = Pattern.compile("^(AES)_([0-9]+)_(.*)$");
|
||||||
|
private static final Pattern OPENSSL_AES_CBC_PATTERN = Pattern.compile("^(AES)([0-9]+)$");
|
||||||
|
private static final Pattern OPENSSL_AES_PATTERN = Pattern.compile("^(AES)([0-9]+)-(.*)$");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java-to-OpenSSL cipher suite conversion map
|
||||||
|
* Note that the Java cipher suite has the protocol prefix (TLS_, SSL_)
|
||||||
|
*/
|
||||||
|
private static final ConcurrentMap<String, String> j2o = PlatformDependent.newConcurrentHashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenSSL-to-Java cipher suite conversion map.
|
||||||
|
* Note that one OpenSSL cipher suite can be converted to more than one Java cipher suites because
|
||||||
|
* a Java cipher suite has the protocol name prefix (TLS_, SSL_)
|
||||||
|
*/
|
||||||
|
private static final ConcurrentMap<String, Map<String, String>> o2j = PlatformDependent.newConcurrentHashMap();
|
||||||
|
|
||||||
|
static {
|
||||||
|
String[] cipherSuites = EmptyArrays.EMPTY_STRINGS;
|
||||||
|
try {
|
||||||
|
cipherSuites = SSLContext.getDefault().getSupportedSSLParameters().getCipherSuites();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
logger.warn("Failed to get the default SSLContext:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the initial mapping from the currently supported cipher suites.
|
||||||
|
for (String c: cipherSuites) {
|
||||||
|
cacheFromJava(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also popluate those unavailable from Java but maybe available in OpenSSL.
|
||||||
|
cacheFromJava("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DHE_DSS_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DHE_RSA_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5");
|
||||||
|
cacheFromJava("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DH_anon_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_DH_anon_WITH_RC4_128_MD5");
|
||||||
|
cacheFromJava("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5");
|
||||||
|
cacheFromJava("SSL_RSA_EXPORT_WITH_RC4_40_MD5");
|
||||||
|
cacheFromJava("SSL_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_RSA_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("SSL_RSA_WITH_NULL_MD5");
|
||||||
|
cacheFromJava("SSL_RSA_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("SSL_RSA_WITH_RC4_128_MD5");
|
||||||
|
cacheFromJava("SSL_RSA_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_DSS_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DHE_RSA_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_DH_anon_WITH_RC4_128_MD5");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("TLS_ECDHE_RSA_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_ECDSA_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_RSA_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_anon_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_anon_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_anon_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("TLS_ECDH_anon_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5");
|
||||||
|
cacheFromJava("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA");
|
||||||
|
cacheFromJava("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5");
|
||||||
|
cacheFromJava("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA");
|
||||||
|
cacheFromJava("TLS_KRB5_EXPORT_WITH_RC4_40_MD5");
|
||||||
|
cacheFromJava("TLS_KRB5_EXPORT_WITH_RC4_40_SHA");
|
||||||
|
cacheFromJava("TLS_KRB5_WITH_3DES_EDE_CBC_MD5");
|
||||||
|
cacheFromJava("TLS_KRB5_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_KRB5_WITH_DES_CBC_MD5");
|
||||||
|
cacheFromJava("TLS_KRB5_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_KRB5_WITH_RC4_128_MD5");
|
||||||
|
cacheFromJava("TLS_KRB5_WITH_RC4_128_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5");
|
||||||
|
cacheFromJava("TLS_RSA_EXPORT_WITH_RC4_40_MD5");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_AES_128_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_AES_128_GCM_SHA256");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_AES_256_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_DES_CBC_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_NULL_MD5");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_NULL_SHA");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_NULL_SHA256");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_RC4_128_MD5");
|
||||||
|
cacheFromJava("TLS_RSA_WITH_RC4_128_SHA");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the cache for testing purpose.
|
||||||
|
*/
|
||||||
|
static void clearCache() {
|
||||||
|
j2o.clear();
|
||||||
|
o2j.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the specified key-value pair has been cached in Java-to-OpenSSL cache.
|
||||||
|
*/
|
||||||
|
static boolean isJ2OCached(String key, String value) {
|
||||||
|
return value.equals(j2o.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the specified key-value pair has been cached in OpenSSL-to-Java cache.
|
||||||
|
*/
|
||||||
|
static boolean isO2JCached(String key, String protocol, String value) {
|
||||||
|
Map<String, String> p2j = o2j.get(key);
|
||||||
|
if (p2j == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return value.equals(p2j.get(protocol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the specified Java cipher suite to its corresponding OpenSSL cipher suite name.
|
||||||
|
*
|
||||||
|
* @return {@code null} if the conversion has failed
|
||||||
|
*/
|
||||||
|
static String toOpenSsl(String javaCipherSuite) {
|
||||||
|
String converted = j2o.get(javaCipherSuite);
|
||||||
|
if (converted != null) {
|
||||||
|
return converted;
|
||||||
|
} else {
|
||||||
|
return cacheFromJava(javaCipherSuite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String cacheFromJava(String javaCipherSuite) {
|
||||||
|
String openSslCipherSuite = toOpenSslUncached(javaCipherSuite);
|
||||||
|
if (openSslCipherSuite == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the mapping.
|
||||||
|
j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite);
|
||||||
|
|
||||||
|
// Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_)
|
||||||
|
final String javaCipherSuiteSuffix = javaCipherSuite.substring(4);
|
||||||
|
Map<String, String> p2j = new HashMap<String, String>(4);
|
||||||
|
p2j.put("", javaCipherSuiteSuffix);
|
||||||
|
p2j.put("SSL", "SSL_" + javaCipherSuiteSuffix);
|
||||||
|
p2j.put("TLS", "TLS_" + javaCipherSuiteSuffix);
|
||||||
|
o2j.put(openSslCipherSuite, p2j);
|
||||||
|
|
||||||
|
logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite, openSslCipherSuite);
|
||||||
|
|
||||||
|
return openSslCipherSuite;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String toOpenSslUncached(String javaCipherSuite) {
|
||||||
|
Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite);
|
||||||
|
if (!m.matches()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String handshakeAlgo = toOpenSslHandshakeAlgo(m.group(1));
|
||||||
|
String bulkCipher = toOpenSslBulkCipher(m.group(2));
|
||||||
|
String hmacAlgo = toOpenSslHmacAlgo(m.group(3));
|
||||||
|
if (handshakeAlgo.length() == 0) {
|
||||||
|
return bulkCipher + '-' + hmacAlgo;
|
||||||
|
} else {
|
||||||
|
return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toOpenSslHandshakeAlgo(String handshakeAlgo) {
|
||||||
|
final boolean export = handshakeAlgo.endsWith("_EXPORT");
|
||||||
|
if (export) {
|
||||||
|
handshakeAlgo = handshakeAlgo.substring(0, handshakeAlgo.length() - 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("RSA".equals(handshakeAlgo)) {
|
||||||
|
handshakeAlgo = "";
|
||||||
|
} else if (handshakeAlgo.endsWith("_anon")) {
|
||||||
|
handshakeAlgo = 'A' + handshakeAlgo.substring(0, handshakeAlgo.length() - 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (export) {
|
||||||
|
if (handshakeAlgo.length() == 0) {
|
||||||
|
handshakeAlgo = "EXP";
|
||||||
|
} else {
|
||||||
|
handshakeAlgo = "EXP-" + handshakeAlgo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handshakeAlgo.replace('_', '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toOpenSslBulkCipher(String bulkCipher) {
|
||||||
|
if (bulkCipher.startsWith("AES_")) {
|
||||||
|
Matcher m = JAVA_AES_CBC_PATTERN.matcher(bulkCipher);
|
||||||
|
if (m.matches()) {
|
||||||
|
return m.replaceFirst("$1$2");
|
||||||
|
}
|
||||||
|
|
||||||
|
m = JAVA_AES_PATTERN.matcher(bulkCipher);
|
||||||
|
if (m.matches()) {
|
||||||
|
return m.replaceFirst("$1$2-$3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("3DES_EDE_CBC".equals(bulkCipher)) {
|
||||||
|
return "DES-CBC3";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("RC4_128".equals(bulkCipher) || "RC4_40".equals(bulkCipher)) {
|
||||||
|
return "RC4";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("DES40_CBC".equals(bulkCipher) || "DES_CBC_40".equals(bulkCipher)) {
|
||||||
|
return "DES-CBC";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("RC2_CBC_40".equals(bulkCipher)) {
|
||||||
|
return "RC2-CBC";
|
||||||
|
}
|
||||||
|
|
||||||
|
return bulkCipher.replace('_', '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toOpenSslHmacAlgo(String hmacAlgo) {
|
||||||
|
// Java and OpenSSL use the same algorithm names for:
|
||||||
|
//
|
||||||
|
// * SHA
|
||||||
|
// * SHA256
|
||||||
|
// * MD5
|
||||||
|
//
|
||||||
|
return hmacAlgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String toJava(String openSslCipherSuite, String protocol) {
|
||||||
|
Map<String, String> p2j = o2j.get(openSslCipherSuite);
|
||||||
|
if (p2j == null) {
|
||||||
|
p2j = cacheFromOpenSsl(openSslCipherSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
String javaCipherSuite = p2j.get(protocol);
|
||||||
|
if (javaCipherSuite == null) {
|
||||||
|
javaCipherSuite = protocol + '_' + p2j.get("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return javaCipherSuite;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> cacheFromOpenSsl(String openSslCipherSuite) {
|
||||||
|
String javaCipherSuiteSuffix = toJavaUncached(openSslCipherSuite);
|
||||||
|
if (javaCipherSuiteSuffix == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix;
|
||||||
|
final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix;
|
||||||
|
|
||||||
|
// Cache the mapping.
|
||||||
|
final Map<String, String> p2j = new HashMap<String, String>(4);
|
||||||
|
p2j.put("", javaCipherSuiteSuffix);
|
||||||
|
p2j.put("SSL", javaCipherSuiteSsl);
|
||||||
|
p2j.put("TLS", javaCipherSuiteTls);
|
||||||
|
o2j.putIfAbsent(openSslCipherSuite, p2j);
|
||||||
|
|
||||||
|
// Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_)
|
||||||
|
j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite);
|
||||||
|
j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite);
|
||||||
|
|
||||||
|
logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls, openSslCipherSuite);
|
||||||
|
logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl, openSslCipherSuite);
|
||||||
|
|
||||||
|
return p2j;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String toJavaUncached(String openSslCipherSuite) {
|
||||||
|
Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite);
|
||||||
|
if (!m.matches()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String handshakeAlgo = m.group(1);
|
||||||
|
final boolean export;
|
||||||
|
if (handshakeAlgo == null) {
|
||||||
|
handshakeAlgo = "";
|
||||||
|
export = false;
|
||||||
|
} else if (handshakeAlgo.startsWith("EXP-")) {
|
||||||
|
handshakeAlgo = handshakeAlgo.substring(4);
|
||||||
|
export = true;
|
||||||
|
} else if ("EXP".equals(handshakeAlgo)) {
|
||||||
|
handshakeAlgo = "";
|
||||||
|
export = true;
|
||||||
|
} else {
|
||||||
|
export = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export);
|
||||||
|
String bulkCipher = toJavaBulkCipher(m.group(2), export);
|
||||||
|
String hmacAlgo = toJavaHmacAlgo(m.group(3));
|
||||||
|
|
||||||
|
return handshakeAlgo + "_WITH_" + bulkCipher + '_' + hmacAlgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toJavaHandshakeAlgo(String handshakeAlgo, boolean export) {
|
||||||
|
if (handshakeAlgo.length() == 0) {
|
||||||
|
handshakeAlgo = "RSA";
|
||||||
|
} else if ("ADH".equals(handshakeAlgo)) {
|
||||||
|
handshakeAlgo = "DH_anon";
|
||||||
|
} else if ("AECDH".equals(handshakeAlgo)) {
|
||||||
|
handshakeAlgo = "ECDH_anon";
|
||||||
|
}
|
||||||
|
|
||||||
|
handshakeAlgo = handshakeAlgo.replace('-', '_');
|
||||||
|
if (export) {
|
||||||
|
return handshakeAlgo + "_EXPORT";
|
||||||
|
} else {
|
||||||
|
return handshakeAlgo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toJavaBulkCipher(String bulkCipher, boolean export) {
|
||||||
|
if (bulkCipher.startsWith("AES")) {
|
||||||
|
Matcher m = OPENSSL_AES_CBC_PATTERN.matcher(bulkCipher);
|
||||||
|
if (m.matches()) {
|
||||||
|
return m.replaceFirst("$1_$2_CBC");
|
||||||
|
}
|
||||||
|
|
||||||
|
m = OPENSSL_AES_PATTERN.matcher(bulkCipher);
|
||||||
|
if (m.matches()) {
|
||||||
|
return m.replaceFirst("$1_$2_$3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("DES-CBC3".equals(bulkCipher)) {
|
||||||
|
return "3DES_EDE_CBC";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("RC4".equals(bulkCipher)) {
|
||||||
|
if (export) {
|
||||||
|
return "RC4_40";
|
||||||
|
} else {
|
||||||
|
return "RC4_128";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("DES-CBC".equals(bulkCipher)) {
|
||||||
|
if (export) {
|
||||||
|
return "DES_CBC_40";
|
||||||
|
} else {
|
||||||
|
return "DES_CBC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("RC2-CBC".equals(bulkCipher)) {
|
||||||
|
if (export) {
|
||||||
|
return "RC2_CBC_40";
|
||||||
|
} else {
|
||||||
|
return "RC2_CBC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bulkCipher.replace('-', '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toJavaHmacAlgo(String hmacAlgo) {
|
||||||
|
// Java and OpenSSL use the same algorithm names for:
|
||||||
|
//
|
||||||
|
// * SHA
|
||||||
|
// * SHA256
|
||||||
|
// * MD5
|
||||||
|
//
|
||||||
|
return hmacAlgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CipherSuiteConverter() { }
|
||||||
|
}
|
@ -105,6 +105,12 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
if (c == null) {
|
if (c == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String converted = CipherSuiteConverter.toOpenSsl(c);
|
||||||
|
if (converted != null) {
|
||||||
|
c = converted;
|
||||||
|
}
|
||||||
|
|
||||||
this.ciphers.add(c);
|
this.ciphers.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,9 +1093,16 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
handshakeFinished = true;
|
handshakeFinished = true;
|
||||||
String c = SSL.getCipherForSSL(ssl);
|
String c = SSL.getCipherForSSL(ssl);
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
|
String protocol = toProtocolFamily(SSL.getVersion(ssl));
|
||||||
|
String converted = CipherSuiteConverter.toJava(c, protocol);
|
||||||
|
if (converted != null) {
|
||||||
|
c = converted;
|
||||||
|
} else {
|
||||||
|
c = protocol + '_' + c.replace('-', '_');
|
||||||
|
}
|
||||||
// OpenSSL returns the ciphers seperated by '-' but the JDK SSLEngine does by '_', so replace '-'
|
// OpenSSL returns the ciphers seperated by '-' but the JDK SSLEngine does by '_', so replace '-'
|
||||||
// with '_' to match the behaviour.
|
// with '_' to match the behaviour.
|
||||||
cipher = CIPHER_REPLACE_PATTERN.matcher(c).replaceAll("_");
|
cipher = c;
|
||||||
}
|
}
|
||||||
String applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
String applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
||||||
if (applicationProtocol == null) {
|
if (applicationProtocol == null) {
|
||||||
@ -1128,6 +1135,27 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
return NOT_HANDSHAKING;
|
return NOT_HANDSHAKING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
|
||||||
|
*/
|
||||||
|
private static String toProtocolFamily(String protocolVersion) {
|
||||||
|
final char c;
|
||||||
|
if (protocolVersion == null || protocolVersion.length() == 0) {
|
||||||
|
c = 0;
|
||||||
|
} else {
|
||||||
|
c = protocolVersion.charAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'T':
|
||||||
|
return "TLS";
|
||||||
|
case 'S':
|
||||||
|
return "SSL";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUseClientMode(boolean clientMode) {
|
public void setUseClientMode(boolean clientMode) {
|
||||||
if (clientMode != this.clientMode) {
|
if (clientMode != this.clientMode) {
|
||||||
|
@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class CipherSuiteConverterTest {
|
||||||
|
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverterTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJ2OMappings() throws Exception {
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH-ECDSA-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "ECDH-RSA-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "DHE-RSA-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDHE-ECDSA-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDHE-RSA-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_RSA_WITH_AES_128_CBC_SHA", "AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "ECDH-ECDSA-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "ECDH-RSA-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDHE-RSA-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH-ECDSA-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "ECDH-RSA-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "DHE-DSS-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-ECDSA-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-RSA-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDH-ECDSA-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "ECDH-RSA-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "DHE-RSA-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "DHE-DSS-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "ECDHE-ECDSA-RC4-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_RC4_128_SHA", "ECDHE-RSA-RC4-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_WITH_RC4_128_SHA", "RC4-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "ECDH-ECDSA-RC4-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_RC4_128_SHA", "ECDH-RSA-RC4-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_WITH_RC4_128_MD5", "RC4-MD5");
|
||||||
|
testJ2OMapping("TLS_DH_anon_WITH_AES_128_GCM_SHA256", "ADH-AES128-GCM-SHA256");
|
||||||
|
testJ2OMapping("TLS_DH_anon_WITH_AES_128_CBC_SHA256", "ADH-AES128-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "AECDH-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_DH_anon_WITH_AES_128_CBC_SHA", "ADH-AES128-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "AECDH-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", "ADH-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_anon_WITH_RC4_128_SHA", "AECDH-RC4-SHA");
|
||||||
|
testJ2OMapping("SSL_DH_anon_WITH_RC4_128_MD5", "ADH-RC4-MD5");
|
||||||
|
testJ2OMapping("SSL_RSA_WITH_DES_CBC_SHA", "DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_DHE_RSA_WITH_DES_CBC_SHA", "DHE-RSA-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_DHE_DSS_WITH_DES_CBC_SHA", "DHE-DSS-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_DH_anon_WITH_DES_CBC_SHA", "ADH-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-DHE-RSA-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "EXP-DHE-DSS-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "EXP-ADH-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_EXPORT_WITH_RC4_40_MD5", "EXP-RC4-MD5");
|
||||||
|
testJ2OMapping("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", "EXP-ADH-RC4-MD5");
|
||||||
|
testJ2OMapping("TLS_RSA_WITH_NULL_SHA256", "NULL-SHA256");
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_NULL_SHA", "ECDHE-ECDSA-NULL-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_NULL_SHA", "ECDHE-RSA-NULL-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_WITH_NULL_SHA", "NULL-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_NULL_SHA", "ECDH-ECDSA-NULL-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_NULL_SHA", "ECDH-RSA-NULL-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_anon_WITH_NULL_SHA", "AECDH-NULL-SHA");
|
||||||
|
testJ2OMapping("SSL_RSA_WITH_NULL_MD5", "NULL-MD5");
|
||||||
|
testJ2OMapping("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "KRB5-DES-CBC3-SHA");
|
||||||
|
testJ2OMapping("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", "KRB5-DES-CBC3-MD5");
|
||||||
|
testJ2OMapping("TLS_KRB5_WITH_RC4_128_SHA", "KRB5-RC4-SHA");
|
||||||
|
testJ2OMapping("TLS_KRB5_WITH_RC4_128_MD5", "KRB5-RC4-MD5");
|
||||||
|
testJ2OMapping("TLS_KRB5_WITH_DES_CBC_SHA", "KRB5-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("TLS_KRB5_WITH_DES_CBC_MD5", "KRB5-DES-CBC-MD5");
|
||||||
|
testJ2OMapping("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "EXP-KRB5-DES-CBC-SHA");
|
||||||
|
testJ2OMapping("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", "EXP-KRB5-DES-CBC-MD5");
|
||||||
|
testJ2OMapping("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", "EXP-KRB5-RC4-SHA");
|
||||||
|
testJ2OMapping("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "EXP-KRB5-RC4-MD5");
|
||||||
|
testJ2OMapping("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-RC2-CBC-MD5");
|
||||||
|
testJ2OMapping("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_DH_anon_WITH_AES_256_CBC_SHA", "ADH-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDHE-ECDSA-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDHE-RSA-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "ECDH-ECDSA-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "ECDH-RSA-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "AECDH-AES256-SHA");
|
||||||
|
testJ2OMapping("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-KRB5-RC2-CBC-MD5");
|
||||||
|
testJ2OMapping("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", "EXP-KRB5-RC2-CBC-SHA");
|
||||||
|
testJ2OMapping("TLS_RSA_WITH_AES_256_CBC_SHA", "AES256-SHA");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testJ2OMapping(String javaCipherSuite, String openSslCipherSuite) {
|
||||||
|
final String actual = CipherSuiteConverter.toOpenSslUncached(javaCipherSuite);
|
||||||
|
logger.info("{} => {}", javaCipherSuite, actual);
|
||||||
|
assertThat(actual, is(openSslCipherSuite));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testO2JMappings() throws Exception {
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256");
|
||||||
|
testO2JMapping("RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH-ECDSA-AES128-SHA256");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_AES_128_CBC_SHA256", "ECDH-RSA-AES128-SHA256");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_AES_128_CBC_SHA256", "DHE-RSA-AES128-SHA256");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDHE-ECDSA-AES128-SHA");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDHE-RSA-AES128-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_AES_128_CBC_SHA", "AES128-SHA");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_AES_128_CBC_SHA", "ECDH-ECDSA-AES128-SHA");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_AES_128_CBC_SHA", "ECDH-RSA-AES128-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDHE-RSA-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH-ECDSA-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_AES_128_GCM_SHA256", "ECDH-RSA-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_AES_128_GCM_SHA256", "DHE-DSS-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-ECDSA-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-RSA-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDH-ECDSA-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "ECDH-RSA-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_3DES_EDE_CBC_SHA", "DHE-RSA-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_3DES_EDE_CBC_SHA", "DHE-DSS-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_RC4_128_SHA", "ECDHE-ECDSA-RC4-SHA");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_RC4_128_SHA", "ECDHE-RSA-RC4-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_RC4_128_SHA", "RC4-SHA");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_RC4_128_SHA", "ECDH-ECDSA-RC4-SHA");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_RC4_128_SHA", "ECDH-RSA-RC4-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_RC4_128_MD5", "RC4-MD5");
|
||||||
|
testO2JMapping("DH_anon_WITH_AES_128_GCM_SHA256", "ADH-AES128-GCM-SHA256");
|
||||||
|
testO2JMapping("DH_anon_WITH_AES_128_CBC_SHA256", "ADH-AES128-SHA256");
|
||||||
|
testO2JMapping("ECDH_anon_WITH_AES_128_CBC_SHA", "AECDH-AES128-SHA");
|
||||||
|
testO2JMapping("DH_anon_WITH_AES_128_CBC_SHA", "ADH-AES128-SHA");
|
||||||
|
testO2JMapping("ECDH_anon_WITH_3DES_EDE_CBC_SHA", "AECDH-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("DH_anon_WITH_3DES_EDE_CBC_SHA", "ADH-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("ECDH_anon_WITH_RC4_128_SHA", "AECDH-RC4-SHA");
|
||||||
|
testO2JMapping("DH_anon_WITH_RC4_128_MD5", "ADH-RC4-MD5");
|
||||||
|
testO2JMapping("RSA_WITH_DES_CBC_SHA", "DES-CBC-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_DES_CBC_SHA", "DHE-RSA-DES-CBC-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_DES_CBC_SHA", "DHE-DSS-DES-CBC-SHA");
|
||||||
|
testO2JMapping("DH_anon_WITH_DES_CBC_SHA", "ADH-DES-CBC-SHA");
|
||||||
|
testO2JMapping("RSA_EXPORT_WITH_DES_CBC_40_SHA", "EXP-DES-CBC-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_EXPORT_WITH_DES_CBC_40_SHA", "EXP-DHE-RSA-DES-CBC-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_EXPORT_WITH_DES_CBC_40_SHA", "EXP-DHE-DSS-DES-CBC-SHA");
|
||||||
|
testO2JMapping("DH_anon_EXPORT_WITH_DES_CBC_40_SHA", "EXP-ADH-DES-CBC-SHA");
|
||||||
|
testO2JMapping("RSA_EXPORT_WITH_RC4_40_MD5", "EXP-RC4-MD5");
|
||||||
|
testO2JMapping("DH_anon_EXPORT_WITH_RC4_40_MD5", "EXP-ADH-RC4-MD5");
|
||||||
|
testO2JMapping("RSA_WITH_NULL_SHA256", "NULL-SHA256");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_NULL_SHA", "ECDHE-ECDSA-NULL-SHA");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_NULL_SHA", "ECDHE-RSA-NULL-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_NULL_SHA", "NULL-SHA");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_NULL_SHA", "ECDH-ECDSA-NULL-SHA");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_NULL_SHA", "ECDH-RSA-NULL-SHA");
|
||||||
|
testO2JMapping("ECDH_anon_WITH_NULL_SHA", "AECDH-NULL-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_NULL_MD5", "NULL-MD5");
|
||||||
|
testO2JMapping("KRB5_WITH_3DES_EDE_CBC_SHA", "KRB5-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("KRB5_WITH_3DES_EDE_CBC_MD5", "KRB5-DES-CBC3-MD5");
|
||||||
|
testO2JMapping("KRB5_WITH_RC4_128_SHA", "KRB5-RC4-SHA");
|
||||||
|
testO2JMapping("KRB5_WITH_RC4_128_MD5", "KRB5-RC4-MD5");
|
||||||
|
testO2JMapping("KRB5_WITH_DES_CBC_SHA", "KRB5-DES-CBC-SHA");
|
||||||
|
testO2JMapping("KRB5_WITH_DES_CBC_MD5", "KRB5-DES-CBC-MD5");
|
||||||
|
testO2JMapping("KRB5_EXPORT_WITH_DES_CBC_40_SHA", "EXP-KRB5-DES-CBC-SHA");
|
||||||
|
testO2JMapping("KRB5_EXPORT_WITH_DES_CBC_40_MD5", "EXP-KRB5-DES-CBC-MD5");
|
||||||
|
testO2JMapping("KRB5_EXPORT_WITH_RC4_40_SHA", "EXP-KRB5-RC4-SHA");
|
||||||
|
testO2JMapping("KRB5_EXPORT_WITH_RC4_40_MD5", "EXP-KRB5-RC4-MD5");
|
||||||
|
testO2JMapping("RSA_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-RC2-CBC-MD5");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA");
|
||||||
|
testO2JMapping("DH_anon_WITH_AES_256_CBC_SHA", "ADH-AES256-SHA");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDHE-ECDSA-AES256-SHA");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDHE-RSA-AES256-SHA");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_AES_256_CBC_SHA", "ECDH-ECDSA-AES256-SHA");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_AES_256_CBC_SHA", "ECDH-RSA-AES256-SHA");
|
||||||
|
testO2JMapping("ECDH_anon_WITH_AES_256_CBC_SHA", "AECDH-AES256-SHA");
|
||||||
|
testO2JMapping("KRB5_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-KRB5-RC2-CBC-MD5");
|
||||||
|
testO2JMapping("KRB5_EXPORT_WITH_RC2_CBC_40_SHA", "EXP-KRB5-RC2-CBC-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_AES_256_CBC_SHA", "AES256-SHA");
|
||||||
|
|
||||||
|
// Test the known mappings that actually do not exist in Java
|
||||||
|
testO2JMapping("EDH_DSS_WITH_3DES_EDE_CBC_SHA", "EDH-DSS-DES-CBC3-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_SEED_SHA", "SEED-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_CAMELLIA128_SHA", "CAMELLIA128-SHA");
|
||||||
|
testO2JMapping("RSA_WITH_IDEA_CBC_SHA", "IDEA-CBC-SHA");
|
||||||
|
testO2JMapping("PSK_WITH_AES_128_CBC_SHA", "PSK-AES128-CBC-SHA");
|
||||||
|
testO2JMapping("PSK_WITH_3DES_EDE_CBC_SHA", "PSK-3DES-EDE-CBC-SHA");
|
||||||
|
testO2JMapping("KRB5_WITH_IDEA_CBC_SHA", "KRB5-IDEA-CBC-SHA");
|
||||||
|
testO2JMapping("KRB5_WITH_IDEA_CBC_MD5", "KRB5-IDEA-CBC-MD5");
|
||||||
|
testO2JMapping("PSK_WITH_RC4_128_SHA", "PSK-RC4-SHA");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_AES_256_GCM_SHA384", "ECDHE-RSA-AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDHE-RSA-AES256-SHA384");
|
||||||
|
testO2JMapping("ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDHE-ECDSA-AES256-SHA384");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_AES_256_GCM_SHA384", "DHE-DSS-AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_AES_256_CBC_SHA256", "DHE-RSA-AES256-SHA256");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_AES_256_CBC_SHA256", "DHE-DSS-AES256-SHA256");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_CAMELLIA256_SHA", "DHE-RSA-CAMELLIA256-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_CAMELLIA256_SHA", "DHE-DSS-CAMELLIA256-SHA");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_AES_256_GCM_SHA384", "ECDH-RSA-AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "ECDH-ECDSA-AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("ECDH_RSA_WITH_AES_256_CBC_SHA384", "ECDH-RSA-AES256-SHA384");
|
||||||
|
testO2JMapping("ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "ECDH-ECDSA-AES256-SHA384");
|
||||||
|
testO2JMapping("RSA_WITH_AES_256_GCM_SHA384", "AES256-GCM-SHA384");
|
||||||
|
testO2JMapping("RSA_WITH_AES_256_CBC_SHA256", "AES256-SHA256");
|
||||||
|
testO2JMapping("RSA_WITH_CAMELLIA256_SHA", "CAMELLIA256-SHA");
|
||||||
|
testO2JMapping("PSK_WITH_AES_256_CBC_SHA", "PSK-AES256-CBC-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_SEED_SHA", "DHE-RSA-SEED-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_SEED_SHA", "DHE-DSS-SEED-SHA");
|
||||||
|
testO2JMapping("DHE_RSA_WITH_CAMELLIA128_SHA", "DHE-RSA-CAMELLIA128-SHA");
|
||||||
|
testO2JMapping("DHE_DSS_WITH_CAMELLIA128_SHA", "DHE-DSS-CAMELLIA128-SHA");
|
||||||
|
testO2JMapping("EDH_RSA_WITH_3DES_EDE_CBC_SHA", "EDH-RSA-DES-CBC3-SHA");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testO2JMapping(String javaCipherSuite, String openSslCipherSuite) {
|
||||||
|
final String actual = CipherSuiteConverter.toJavaUncached(openSslCipherSuite);
|
||||||
|
logger.info("{} => {}", openSslCipherSuite, actual);
|
||||||
|
assertThat(actual, is(javaCipherSuite));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCachedJ2OMappings() {
|
||||||
|
testCachedJ2OMapping("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testCachedJ2OMapping(String javaCipherSuite, String openSslCipherSuite) {
|
||||||
|
CipherSuiteConverter.clearCache();
|
||||||
|
|
||||||
|
final String actual1 = CipherSuiteConverter.toOpenSsl(javaCipherSuite);
|
||||||
|
assertThat(actual1, is(openSslCipherSuite));
|
||||||
|
|
||||||
|
// Ensure that the cache entries have been created.
|
||||||
|
assertThat(CipherSuiteConverter.isJ2OCached(javaCipherSuite, actual1), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isO2JCached(actual1, "", javaCipherSuite.substring(4)), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isO2JCached(actual1, "SSL", "SSL_" + javaCipherSuite.substring(4)), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isO2JCached(actual1, "TLS", "TLS_" + javaCipherSuite.substring(4)), is(true));
|
||||||
|
|
||||||
|
final String actual2 = CipherSuiteConverter.toOpenSsl(javaCipherSuite);
|
||||||
|
assertThat(actual2, is(openSslCipherSuite));
|
||||||
|
|
||||||
|
// Test if the returned cipher strings are identical,
|
||||||
|
// so that the TLS sessions with the same cipher suite do not create many strings.
|
||||||
|
assertThat(actual1, is(sameInstance(actual2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCachedO2JMappings() {
|
||||||
|
testCachedO2JMapping("ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testCachedO2JMapping(String javaCipherSuite, String openSslCipherSuite) {
|
||||||
|
CipherSuiteConverter.clearCache();
|
||||||
|
|
||||||
|
final String tlsExpected = "TLS_" + javaCipherSuite;
|
||||||
|
final String sslExpected = "SSL_" + javaCipherSuite;
|
||||||
|
|
||||||
|
final String tlsActual1 = CipherSuiteConverter.toJava(openSslCipherSuite, "TLS");
|
||||||
|
final String sslActual1 = CipherSuiteConverter.toJava(openSslCipherSuite, "SSL");
|
||||||
|
assertThat(tlsActual1, is(tlsExpected));
|
||||||
|
assertThat(sslActual1, is(sslExpected));
|
||||||
|
|
||||||
|
// Ensure that the cache entries have been created.
|
||||||
|
assertThat(CipherSuiteConverter.isO2JCached(openSslCipherSuite, "", javaCipherSuite), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isO2JCached(openSslCipherSuite, "SSL", sslExpected), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isO2JCached(openSslCipherSuite, "TLS", tlsExpected), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isJ2OCached(tlsExpected, openSslCipherSuite), is(true));
|
||||||
|
assertThat(CipherSuiteConverter.isJ2OCached(sslExpected, openSslCipherSuite), is(true));
|
||||||
|
|
||||||
|
final String tlsActual2 = CipherSuiteConverter.toJava(openSslCipherSuite, "TLS");
|
||||||
|
final String sslActual2 = CipherSuiteConverter.toJava(openSslCipherSuite, "SSL");
|
||||||
|
assertThat(tlsActual2, is(tlsExpected));
|
||||||
|
assertThat(sslActual2, is(sslExpected));
|
||||||
|
|
||||||
|
// Test if the returned cipher strings are identical,
|
||||||
|
// so that the TLS sessions with the same cipher suite do not create many strings.
|
||||||
|
assertThat(tlsActual1, is(sameInstance(tlsActual2)));
|
||||||
|
assertThat(sslActual1, is(sameInstance(sslActual2)));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user