/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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 org.apache.tomcat.util.net.openssl.ciphers; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; 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 org.apache.catalina.util.IOTools; import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; public class TesterOpenSSL { public static final int VERSION; public static final Set<Cipher> OPENSSL_UNIMPLEMENTED_CIPHERS; public static final Map<String,String> OPENSSL_RENAMED_CIPHERS; static { // Note: The following lists are intended to be aligned with the most // recent release of each OpenSSL release branch. Running the unit // tests with earlier releases is likely to result in failures. String versionString = null; try { versionString = executeOpenSSLCommand("version"); } catch (IOException e) { versionString = ""; } if (versionString.startsWith("OpenSSL 1.1.1")) { // Note: Gump currently tests 9.0.x with OpenSSL master // (a.k.a 1.1.1-dev) VERSION = 10101; } else if (versionString.startsWith("OpenSSL 1.1.0")) { // Support ends 2018-04-30 VERSION = 10100; } else if (versionString.startsWith("OpenSSL 1.0.2")) { // Support ends 2019-12-31 (LTS) // Note: Gump current tests 8.0.x with OpenSSL 1.0.2 VERSION = 10002; } else if (versionString.startsWith("OpenSSL 1.0.1")) { // Support ends 2016-12-31 VERSION = 10001; // Note: Release branches 1.0.0 and earlier are no longer supported by // the OpenSSL team so these tests don't support them either. } else { VERSION = -1; } HashSet<Cipher> unimplemented = new HashSet<>(); // These have been removed from all supported versions. unimplemented.add(Cipher.TLS_DHE_DSS_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5); unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA); unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA); unimplemented.add(Cipher.TLS_RSA_EXPORT1024_WITH_RC4_56_MD5); unimplemented.add(Cipher.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_anon_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA); unimplemented.add(Cipher.TLS_DH_anon_EXPORT_WITH_RC4_40_MD5); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_DSS_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_WITH_DES_CBC_SHA); unimplemented.add(Cipher.SSL2_DES_64_CBC_WITH_MD5); unimplemented.add(Cipher.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5); unimplemented.add(Cipher.TLS_RSA_EXPORT_WITH_RC4_40_MD5); unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5); unimplemented.add(Cipher.SSL_CK_RC2_128_CBC_WITH_MD5); unimplemented.add(Cipher.SSL_CK_RC4_128_WITH_MD5); unimplemented.add(Cipher.SSL2_RC4_128_EXPORT40_WITH_MD5); unimplemented.add(Cipher.SSL2_IDEA_128_CBC_WITH_MD5); unimplemented.add(Cipher.SSL2_DES_192_EDE3_CBC_WITH_MD5); if (VERSION < 10002) { // These were implemented in 1.0.2 so won't be available in any // earlier version unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_SEED_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_DES_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_SEED_CBC_SHA); } else { // These were removed in 1.0.2 so won't be available from that // version onwards. // None at present. } if (VERSION < 10100) { // These were implemented in 1.1.0 so won't be available in any // earlier version unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CBC_SHA384); unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA256); unimplemented.add(Cipher.TLS_PSK_WITH_NULL_SHA384); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA256); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_NULL_SHA384); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA256); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_NULL_SHA384); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA256); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_NULL_SHA384); unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256); unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256); unimplemented.add(Cipher.TLS_RSA_WITH_AES_128_CCM); unimplemented.add(Cipher.TLS_RSA_WITH_AES_256_CCM); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CCM); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CCM); unimplemented.add(Cipher.TLS_RSA_WITH_AES_128_CCM_8); unimplemented.add(Cipher.TLS_RSA_WITH_AES_256_CCM_8); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CCM_8); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CCM_8); unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CCM); unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CCM); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_128_CCM); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_AES_256_CCM); unimplemented.add(Cipher.TLS_PSK_WITH_AES_128_CCM_8); unimplemented.add(Cipher.TLS_PSK_WITH_AES_256_CCM_8); unimplemented.add(Cipher.TLS_PSK_DHE_WITH_AES_128_CCM_8); unimplemented.add(Cipher.TLS_PSK_DHE_WITH_AES_256_CCM_8); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CCM); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8); unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256); unimplemented.add(Cipher.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256); } else { // These were removed in 1.1.0 so won't be available from that // version onwards. unimplemented.add(Cipher.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_DSS_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_DSS_WITH_SEED_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_CBC_SHA256); unimplemented.add(Cipher.TLS_DH_RSA_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA); unimplemented.add(Cipher.TLS_DH_RSA_WITH_SEED_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_NULL_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_NULL_SHA); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256); unimplemented.add(Cipher.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384); unimplemented.add(Cipher.TLS_RSA_WITH_RC4_128_MD5); unimplemented.add(Cipher.TLS_DH_anon_WITH_RC4_128_MD5); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_RSA_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_RC4_128_SHA); unimplemented.add(Cipher.TLS_ECDH_anon_WITH_RC4_128_SHA); // 3DES requires a compile time switch to enable. Treat as removed. unimplemented.add(Cipher.TLS_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_RSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA); unimplemented.add(Cipher.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA); } OPENSSL_UNIMPLEMENTED_CIPHERS = Collections.unmodifiableSet(unimplemented); Map<String,String> renamed = new HashMap<>(); renamed.put("ECDH-ECDSA-RC4-SHA+SSLv3", "ECDH-ECDSA-RC4-SHA+TLSv1"); renamed.put("ECDHE-ECDSA-NULL-SHA+SSLv3", "ECDHE-ECDSA-NULL-SHA+TLSv1"); renamed.put("ECDHE-ECDSA-DES-CBC3-SHA+SSLv3", "ECDHE-ECDSA-DES-CBC3-SHA+TLSv1"); renamed.put("ECDHE-ECDSA-AES128-SHA+SSLv3", "ECDHE-ECDSA-AES128-SHA+TLSv1"); renamed.put("ECDHE-ECDSA-AES256-SHA+SSLv3", "ECDHE-ECDSA-AES256-SHA+TLSv1"); renamed.put("ECDHE-RSA-NULL-SHA+SSLv3", "ECDHE-RSA-NULL-SHA+TLSv1"); renamed.put("ECDHE-RSA-RC4-SHA+SSLv3", "ECDHE-RSA-RC4-SHA+TLSv1"); renamed.put("ECDHE-RSA-DES-CBC3-SHA+SSLv3", "ECDHE-RSA-DES-CBC3-SHA+TLSv1"); renamed.put("ECDHE-RSA-AES128-SHA+SSLv3", "ECDHE-RSA-AES128-SHA+TLSv1"); renamed.put("ECDHE-RSA-AES256-SHA+SSLv3", "ECDHE-RSA-AES256-SHA+TLSv1"); renamed.put("AECDH-NULL-SHA+SSLv3", "AECDH-NULL-SHA+TLSv1"); renamed.put("AECDH-RC4-SHA+SSLv3", "AECDH-RC4-SHA+TLSv1"); renamed.put("AECDH-DES-CBC3-SHA+SSLv3", "AECDH-DES-CBC3-SHA+TLSv1"); renamed.put("AECDH-AES128-SHA+SSLv3", "AECDH-AES128-SHA+TLSv1"); renamed.put("AECDH-AES256-SHA+SSLv3", "AECDH-AES256-SHA+TLSv1"); renamed.put("ECDHE-PSK-RC4-SHA+SSLv3", "ECDHE-PSK-RC4-SHA+TLSv1"); renamed.put("ECDHE-PSK-3DES-EDE-CBC-SHA+SSLv3", "ECDHE-PSK-3DES-EDE-CBC-SHA+TLSv1"); renamed.put("ECDHE-PSK-AES128-CBC-SHA+SSLv3", "ECDHE-PSK-AES128-CBC-SHA+TLSv1"); renamed.put("ECDHE-PSK-AES256-CBC-SHA+SSLv3", "ECDHE-PSK-AES256-CBC-SHA+TLSv1"); renamed.put("ECDHE-PSK-NULL-SHA+SSLv3", "ECDHE-PSK-NULL-SHA+TLSv1"); OPENSSL_RENAMED_CIPHERS = Collections.unmodifiableMap(renamed); } private TesterOpenSSL() { // Utility class. Hide default constructor. } public static Set<String> getOpenSSLCiphersAsSet(String specification) throws Exception { String[] ciphers = getOpenSSLCiphersAsExpression(specification).trim().split(":"); Set<String> result = new HashSet<>(ciphers.length); for (String cipher : ciphers) { result.add(cipher); } return result; } public static String getOpenSSLCiphersAsExpression(String specification) throws Exception { String stdout; if (specification == null) { stdout = executeOpenSSLCommand("ciphers", "-v"); } else { stdout = executeOpenSSLCommand("ciphers", "-v", specification); } if (stdout.length() == 0) { return stdout; } StringBuilder output = new StringBuilder(); boolean first = true; // OpenSSL should have returned one cipher per line String ciphers[] = stdout.split("\n"); for (String cipher : ciphers) { // Handle rename for 1.1.0 onwards cipher = cipher.replaceAll("EDH", "DHE"); if (first) { first = false; } else { output.append(':'); } StringBuilder name = new StringBuilder(); // Name is first part int i = cipher.indexOf(' '); name.append(cipher.substring(0, i)); // Advance i past the space while (Character.isWhitespace(cipher.charAt(i))) { i++; } // Protocol is the second int j = cipher.indexOf(' ', i); name.append('+'); name.append(cipher.substring(i, j)); // More renames if (OPENSSL_RENAMED_CIPHERS.containsKey(name.toString())) { output.append(OPENSSL_RENAMED_CIPHERS.get(name.toString())); } else { output.append(name.toString()); } } return output.toString(); } /* * Use this method to filter parser results when comparing them to OpenSSL * results to take account of unimplemented cipher suites. */ public static void removeUnimplementedCiphersJsse(List<String> list) { for (Cipher cipher : OPENSSL_UNIMPLEMENTED_CIPHERS) { for (String jsseName : cipher.getJsseNames()) { list.remove(jsseName); } } } private static String executeOpenSSLCommand(String... args) throws IOException { String openSSLPath = System.getProperty("tomcat.test.openssl.path"); String openSSLLibPath = null; if (openSSLPath == null || openSSLPath.length() == 0) { openSSLPath = "openssl"; } else { // Explicit OpenSSL path may also need explicit lib path // (e.g. Gump needs this) openSSLLibPath = openSSLPath.substring(0, openSSLPath.lastIndexOf('/')); openSSLLibPath = openSSLLibPath + "/../lib"; } List<String> cmd = new ArrayList<>(); cmd.add(openSSLPath); for (String arg : args) { cmd.add(arg); } ProcessBuilder pb = new ProcessBuilder(cmd.toArray(new String[cmd.size()])); if (openSSLLibPath != null) { Map<String,String> env = pb.environment(); String libraryPath = env.get("LD_LIBRARY_PATH"); if (libraryPath == null) { libraryPath = openSSLLibPath; } else { libraryPath = libraryPath + ":" + openSSLLibPath; } env.put("LD_LIBRARY_PATH", libraryPath); } Process p = pb.start(); InputStreamToText stdout = new InputStreamToText(p.getInputStream()); InputStreamToText stderr = new InputStreamToText(p.getErrorStream()); Thread t1 = new Thread(stdout); t1.setName("OpenSSL stdout reader"); t1.start(); Thread t2 = new Thread(stderr); t2.setName("OpenSSL stderr reader"); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { throw new IOException(e); } String errorText = stderr.getText(); if (errorText.length() > 0) { System.err.println(errorText); } return stdout.getText().trim(); } private static class InputStreamToText implements Runnable { private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); private final InputStream is; InputStreamToText(InputStream is) { this.is = is; } @Override public void run() { try { IOTools.flow(is, baos); } catch (IOException e) { // Ignore } } public String getText() { return baos.toString(); } } }