This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,620 @@
/*
* 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.util.List;
import java.util.TreeSet;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
public class TestOpenSSLCipherConfigurationParser {
@Test
public void testDEFAULT() throws Exception {
if (TesterOpenSSL.VERSION < 10100) {
// Account for classes of ciphers removed from DEFAULT in 1.1.0
testSpecification("DEFAULT:!RC4:!DSS:!SEED:!IDEA:!CAMELLIA:!AESCCM:!3DES");
} else {
testSpecification("DEFAULT");
}
}
@Test
public void testCOMPLEMENTOFDEFAULT() throws Exception {
if (TesterOpenSSL.VERSION < 10100) {
// Account for classes of ciphers removed from DEFAULT in 1.1.0
testSpecification("COMPLEMENTOFDEFAULT:RC4:DSS:SEED:IDEA:CAMELLIA:AESCCM:aNULL:3DES");
} else {
testSpecification("COMPLEMENTOFDEFAULT");
}
}
@Test
public void testALL() throws Exception {
testSpecification("ALL");
}
@Test
public void testCOMPLEMENTOFALL() throws Exception {
testSpecification("COMPLEMENTOFALL");
}
@Test
public void testaNULL() throws Exception {
testSpecification("aNULL");
}
@Test
public void testeNULL() throws Exception {
testSpecification("eNULL");
}
@Test
public void testHIGH() throws Exception {
testSpecification("HIGH");
}
@Test
public void testMEDIUM() throws Exception {
testSpecification("MEDIUM");
}
@Test
public void testLOW() throws Exception {
testSpecification("LOW");
}
@Test
public void testEXPORT40() throws Exception {
testSpecification("EXPORT40");
}
@Test
public void testEXPORT() throws Exception {
testSpecification("EXPORT");
}
@Test
public void testRSA() throws Exception {
testSpecification("RSA");
}
@Test
public void testaRSA() throws Exception {
testSpecification("aRSA");
}
@Test
public void testkRSA() throws Exception {
testSpecification("kRSA");
}
@Test
public void testkEDH() throws Exception {
testSpecification("kEDH");
}
@Test
public void testkDHE() throws Exception {
// This alias was introduced in 1.0.2
if (TesterOpenSSL.VERSION >= 10002) {
testSpecification("kDHE");
}
}
@Test
public void testEDH() throws Exception {
testSpecification("EDH");
}
@Test
public void testDHE() throws Exception {
// This alias was introduced in 1.0.2
if (TesterOpenSSL.VERSION >= 10002) {
testSpecification("DHE");
}
}
@Test
public void testkDHr() throws Exception {
testSpecification("kDHr");
}
@Test
public void testkDHd() throws Exception {
testSpecification("kDHd");
}
@Test
public void testkDH() throws Exception {
testSpecification("kDH");
}
@Test
public void testkECDHr() throws Exception {
testSpecification("kECDHr");
}
@Test
public void testkECDHe() throws Exception {
testSpecification("kECDHe");
}
@Test
public void testkECDH() throws Exception {
testSpecification("kECDH");
}
@Test
public void testkEECDH() throws Exception {
testSpecification("kEECDH");
}
@Test
public void testECDH() throws Exception {
testSpecification("ECDH");
}
@Test
public void testkECDHE() throws Exception {
testSpecification("kECDHE");
}
@Test
public void testECDHE() throws Exception {
testSpecification("ECDHE");
}
@Test
@Ignore("Contrary to the docs, OpenSSL does not recognise EECDHE")
public void testEECDHE() throws Exception {
testSpecification("EECDHE");
}
@Test
public void testAECDH() throws Exception {
testSpecification("AECDH");
}
@Test
public void testDSS() throws Exception {
testSpecification("DSS");
}
@Test
public void testaDSS() throws Exception {
testSpecification("aDSS");
}
@Test
public void testaDH() throws Exception {
testSpecification("aDH");
}
@Test
public void testaECDH() throws Exception {
testSpecification("aECDH");
}
@Test
public void testaECDSA() throws Exception {
testSpecification("aECDSA");
}
@Test
public void testECDSA() throws Exception {
testSpecification("ECDSA");
}
@Test
public void testkFZA() throws Exception {
testSpecification("kFZA");
}
@Test
public void testaFZA() throws Exception {
testSpecification("aFZA");
}
@Test
public void testeFZA() throws Exception {
testSpecification("eFZA");
}
@Test
public void testFZA() throws Exception {
testSpecification("FZA");
}
@Test
public void testTLSv1_2() throws Exception {
testSpecification("TLSv1.2");
}
@Test
public void testTLSv1() throws Exception {
// In OpenSSL 1.1.0-dev, TLSv1 refers to those ciphers that require
// TLSv1 rather than being an alias for SSLv3
if (TesterOpenSSL.VERSION >= 10100) {
testSpecification("TLSv1");
}
}
@Test
public void testSSLv2() throws Exception {
testSpecification("SSLv2");
}
@Test
public void testSSLv3() throws Exception {
// In OpenSSL 1.1.0-dev, TLSv1 refers to those ciphers that require
// TLSv1 rather than being an alias for SSLv3
if (TesterOpenSSL.VERSION < 10100) {
testSpecification("SSLv3:TLSv1");
}
}
@Test
public void testDH() throws Exception {
testSpecification("DH");
}
@Test
public void testADH() throws Exception {
testSpecification("ADH");
}
@Test
public void testAES128() throws Exception {
testSpecification("AES128");
}
@Test
public void testAES256() throws Exception {
testSpecification("AES256");
}
@Test
public void testAES() throws Exception {
testSpecification("AES");
}
@Test
public void testAESGCM() throws Exception {
testSpecification("AESGCM");
}
@Test
public void testAESCCM() throws Exception {
testSpecification("AESCCM");
}
@Test
public void testAESCCM8() throws Exception {
testSpecification("AESCCM8");
}
@Test
public void testCAMELLIA128() throws Exception {
testSpecification("CAMELLIA128");
}
@Test
public void testCAMELLIA256() throws Exception {
testSpecification("CAMELLIA256");
}
@Test
public void testCAMELLIA() throws Exception {
testSpecification("CAMELLIA");
}
@Test
public void testCHACHA20() throws Exception {
testSpecification("CHACHA20");
}
@Test
public void test3DES() throws Exception {
testSpecification("3DES");
}
@Test
public void testDES() throws Exception {
testSpecification("DES");
}
@Test
public void testRC4() throws Exception {
testSpecification("RC4");
}
@Test
public void testRC2() throws Exception {
testSpecification("RC2");
}
@Test
public void testIDEA() throws Exception {
testSpecification("IDEA");
}
@Test
public void testSEED() throws Exception {
testSpecification("SEED");
}
@Test
public void testMD5() throws Exception {
testSpecification("MD5");
}
@Test
public void testSHA1() throws Exception {
testSpecification("SHA1");
}
@Test
public void testSHA() throws Exception {
testSpecification("SHA");
}
@Test
public void testSHA256() throws Exception {
testSpecification("SHA256");
}
@Test
public void testSHA384() throws Exception {
testSpecification("SHA384");
}
@Test
public void testKRB5() throws Exception {
testSpecification("KRB5");
}
@Test
public void testaGOST() throws Exception {
testSpecification("aGOST");
}
@Test
public void testaGOST01() throws Exception {
testSpecification("aGOST01");
}
@Test
public void testaGOST94() throws Exception {
testSpecification("aGOST94");
}
@Test
public void testkGOST() throws Exception {
testSpecification("kGOST");
}
@Test
public void testGOST94() throws Exception {
testSpecification("GOST94");
}
@Test
public void testGOST89MAC() throws Exception {
testSpecification("GOST89MAC");
}
@Test
public void testaPSK() throws Exception {
testSpecification("aPSK");
}
@Test
public void testkPSK() throws Exception {
testSpecification("kPSK");
}
@Test
public void testkRSAPSK() throws Exception {
testSpecification("kRSAPSK");
}
@Test
public void testkECDHEPSK() throws Exception {
testSpecification("kECDHEPSK");
}
@Test
public void testkDHEPSK() throws Exception {
testSpecification("kDHEPSK");
}
@Test
public void testPSK() throws Exception {
testSpecification("PSK");
}
@Test
public void testARIA() throws Exception {
testSpecification("ARIA");
}
@Test
public void testARIA128() throws Exception {
testSpecification("ARIA128");
}
@Test
public void testARIA256() throws Exception {
testSpecification("ARIA256");
}
// TODO: Add tests for the individual operators
@Test
public void testSpecification01() throws Exception {
// Tomcat 8 default as of 2014-08-04
// This gets an A- from https://www.ssllabs.com/ssltest with no FS for
// a number of the reference browsers
testSpecification("HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5");
}
@Test
public void testSpecification02() throws Exception {
// Suggestion from dev list (s/ECDHE/kEECDH/, s/DHE/EDH/
testSpecification("!aNULL:!eNULL:!EXPORT:!DSS:!DES:!SSLv2:kEECDH:ECDH:EDH:AES256-GCM-SHA384:AES128-GCM-SHA256:+RC4:HIGH:aRSA:kECDHr:MEDIUM");
}
@Test
public void testSpecification03() throws Exception {
// Reported as failing during 8.0.11 release vote by Ognjen Blagojevic
// EDH was introduced in 1.0.0
testSpecification("EECDH+aRSA+SHA384:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS");
}
private void testSpecification(String specification) throws Exception {
// Filter out cipher suites that OpenSSL does not implement
String openSSLCipherList = TesterOpenSSL.getOpenSSLCiphersAsExpression(specification);
List<String> jsseCipherListFromOpenSSL =
OpenSSLCipherConfigurationParser.parseExpression(openSSLCipherList);
List<String> jsseCipherListFromParser =
OpenSSLCipherConfigurationParser.parseExpression(specification);
TesterOpenSSL.removeUnimplementedCiphersJsse(jsseCipherListFromParser);
// First check the lists have the same entries
// Order is NOT important at this point. It is checked below.
Assert.assertEquals(
"Expected " + jsseCipherListFromParser.size() + " ciphers but got "
+ jsseCipherListFromOpenSSL.size() + " for the specification '"
+ specification + "'",
new TreeSet<>(jsseCipherListFromParser), new TreeSet<>(jsseCipherListFromOpenSSL));
// OpenSSL treats many ciphers as having equal preference. The order
// returned depends on the order they are requested. The following code
// checks that the Parser produces a cipher list that is consistent with
// OpenSSL's preference order by confirming that running through OpenSSL
// does not change the order.
String parserOrderedExpression = listToString(jsseCipherListFromParser, ',');
Assert.assertEquals(
listToString(OpenSSLCipherConfigurationParser.parseExpression(
parserOrderedExpression), ','),
parserOrderedExpression);
}
private String listToString(List<String> list, char separator) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String entry : list) {
if (first) {
first = false;
} else {
sb.append(separator);
}
sb.append(entry);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.util.LinkedHashSet;
import org.junit.Assert;
import org.junit.Test;
/*
* The unit test is independent of OpenSSL version and does not require OpenSSL
* to be present.
*/
public class TestOpenSSLCipherConfigurationParserOnly {
@Test
public void testDefaultSort01() throws Exception {
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
// Everything else being equal, AES is preferred
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
input.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
Assert.assertEquals(expected.toString(), result.toString());
}
@Test
public void testDefaultSort02() throws Exception {
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
// ECHDE should beat AES
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
input.add(Cipher.TLS_RSA_WITH_AES_256_CBC_SHA);
input.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384);
expected.add(Cipher.TLS_RSA_WITH_AES_256_CBC_SHA);
Assert.assertEquals(expected.toString(), result.toString());
}
@Test
public void testDefaultSort03() throws Exception {
// Reproducing a failure observed on Gump with OpenSSL 1.1.x
// AES should beat CAMELLIA
LinkedHashSet<Cipher> input = new LinkedHashSet<>();
input.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
input.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.defaultSort(input);
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384);
Assert.assertEquals(expected.toString(), result.toString());
}
@Test
public void testRename01() throws Exception {
// EDH -> DHE
LinkedHashSet<Cipher> result =
OpenSSLCipherConfigurationParser.parse("EXP-EDH-DSS-DES-CBC-SHA");
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
Assert.assertEquals(expected, result);
}
@Test
public void testCustomOrdering() throws Exception {
// https://bz.apache.org/bugzilla/show_bug.cgi?id=59081
LinkedHashSet<Cipher> result = OpenSSLCipherConfigurationParser.parse(
"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:" +
"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DES-CBC3-SHA");
LinkedHashSet<Cipher> expected = new LinkedHashSet<>();
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
expected.add(Cipher.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
expected.add(Cipher.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
expected.add(Cipher.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
expected.add(Cipher.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
expected.add(Cipher.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
Assert.assertEquals(expected.toString(), result.toString());
}
}

View File

@@ -0,0 +1,527 @@
/*
* 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.ByteArrayOutputStream;
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;
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 3.0.0")) {
// Note: Gump currently tests 9.0.x with OpenSSL master
// (a.k.a 3.0.0-dev)
VERSION = 30000;
} else if (versionString.startsWith("OpenSSL 1.1.1")) {
// LTS
// Supported until at least 2023-09-11
VERSION = 10101;
} else if (versionString.startsWith("OpenSSL 1.1.0")) {
// Support ends 2019-09-11
VERSION = 10100;
} else if (versionString.startsWith("OpenSSL 1.0.2")) {
// LTS
// Support ends 2019-12-31
// Note: Gump current tests 8.5.x with OpenSSL 1.0.2
VERSION = 10002;
// Note: Release branches 1.0.1 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);
// These are TLS v1.3 cipher suites
// Java does not currently support these so they are excluded from the
// testing.
// Note: If OpenSSL is used then some of these may be available
// depending on the OpenSSL version used and the defaults for that
// version
unimplemented.add(Cipher.TLS_AES_128_CCM_8_SHA256);
unimplemented.add(Cipher.TLS_AES_128_CCM_SHA256);
unimplemented.add(Cipher.TLS_AES_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_AES_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_CHACHA20_POLY1305_SHA256);
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);
}
if (VERSION < 10101) {
// These were implemented in 1.1.1 so won't be available in any
// earlier version
unimplemented.add(Cipher.TLS_RSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_RSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_PSK_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_PSK_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256);
unimplemented.add(Cipher.TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384);
}
String skipCiphers = System.getProperty("tomcat.test.openssl.unimplemented", "");
if (!skipCiphers.isEmpty()) {
String[] skip = skipCiphers.split(",");
for (Cipher c : Cipher.values()) {
for (String s : skip) {
if (c.toString().contains(s)) {
unimplemented.add(c);
}
}
}
}
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 {
List<String> args = new ArrayList<>();
// Standard command to list the ciphers
args.add("ciphers");
args.add("-v");
if (VERSION < 10100) {
// Need to exclude the GOST ciphers
if (specification == null) {
specification = "DEFAULT:!aGOST";
} else {
specification = "!aGOST:" + specification;
}
}
if (VERSION >= 10101) {
// Need to exclude the TLSv1.3 ciphers
args.add("-ciphersuites");
args.add("");
}
// Include the specification if provided
if (specification != null) {
args.add(specification);
}
String stdout = executeOpenSSLCommand(args.toArray(new String[args.size()]));
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();
}
}
}