├── certgen ├── ssl-confs │ ├── empty.cnf │ ├── intermediate.cnf │ ├── root.cnf │ └── server.cnf ├── server-dsa.param ├── server-dsa.key ├── Makefile ├── test │ ├── certgen-test.mk │ └── src │ │ └── TestSSL.java └── certgen.mk ├── .gitignore ├── jtreg-wrappers ├── TEST.ROOT ├── ssl-tests-openssl-client.sh ├── ssl-tests-bcjsse.sh ├── ssl-tests-gnutls-client.sh ├── ssl-tests-bcfips.sh ├── ssl-tests.sh ├── ssl-tests-bc-2nd.sh ├── ssl-tests-nss-client.sh └── SysDepsProps.java ├── SSLContextInfo ├── Makefile ├── SSLContextInfo.mk └── src │ └── SSLContextInfo.java ├── SSLSocketInfo ├── Makefile ├── SSLSocketInfo.mk └── src │ └── SSLSocketInfo.java ├── LICENSE ├── ssl-tests ├── src │ ├── Main.java │ ├── KeystoreUtil.java │ ├── StreamReader.java │ ├── NssClient.java │ ├── SSLSocketClient.java │ ├── SSLSocketServer.java │ ├── GnutlsClient.java │ ├── OpensslClient.java │ ├── ExternalClient.java │ └── SSLSocketTester.java └── ssl-tests.mk ├── README.md ├── run.sh ├── .github └── workflows │ └── test.yaml └── Makefile /certgen/ssl-confs/empty.cnf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | certgen/build 3 | SSLSocketInfo/classes 4 | test.* 5 | jtreg 6 | jtreg*gz 7 | -------------------------------------------------------------------------------- /jtreg-wrappers/TEST.ROOT: -------------------------------------------------------------------------------- 1 | requires.extraPropDefns = SysDepsProps.java 2 | requires.properties = \ 3 | bin.gnutlscli \ 4 | bin.tstclnt 5 | -------------------------------------------------------------------------------- /jtreg-wrappers/ssl-tests-openssl-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # @test 3 | # @requires os.family == "linux" 4 | # @bug 6666666 5 | # @summary ssl-tests with openssl client 6 | # @run shell/timeout=1000 ssl-tests-openssl-client.sh 7 | 8 | set -eu 9 | rm -rf build 10 | export JAVA_HOME="${TESTJAVA}" 11 | make -f "${TESTSRC:-.}/../Makefile" ssl-tests TOP_DIR="${TESTSRC:-.}/.." SSLTESTS_USE_OPENSSL_CLIENT=1 12 | -------------------------------------------------------------------------------- /SSLContextInfo/Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR=src 2 | CLASSES_DIR=classes 3 | 4 | JAVA=java 5 | JAVAC=javac 6 | 7 | MAIN_CLASS = SSLContextInfo 8 | 9 | .PHONY: clean build run 10 | 11 | all: run 12 | 13 | clean: 14 | rm -rf $(CLASSES_DIR) 15 | 16 | build: $(CLASSES_DIR) 17 | 18 | run: $(CLASSES_DIR) 19 | $(JAVA) -cp $< $(MAIN_CLASS) 20 | 21 | $(CLASSES_DIR): $(SRC_DIR) 22 | mkdir $@ 23 | $(JAVAC) -encoding UTF-8 -d $@ $ /dev/null 2>&1 \ 12 | && ! [ -e "/usr/lib64/nss/unsupported-tools/listsuites" ] \ 13 | && ! [ -e "/usr/lib/nss/unsupported-tools/listsuites" ] ; then 14 | # if system does not contain nss listsuites utility, build it 15 | curl -L -f -o listsuites.c https://raw.githubusercontent.com/servo/nss/949eb9848f4fa5f83756f3ab7fdf9b0d3f20d37f/cmd/listsuites/listsuites.c 16 | gcc $( pkg-config --cflags nss ) -o listsuites listsuites.c $( pkg-config --libs nss ) 17 | export PATH="${PATH:-}${PATH:+:}${PWD}" 18 | fi 19 | 20 | export JAVA_HOME="${TESTJAVA}" 21 | make -f "${TESTSRC:-.}/../Makefile" ssl-tests TOP_DIR="${TESTSRC:-.}/.." SSLTESTS_USE_NSS_CLIENT=1 22 | -------------------------------------------------------------------------------- /certgen/ssl-confs/root.cnf: -------------------------------------------------------------------------------- 1 | # https://wiki.openssl.org/index.php/Manual:Req(1) 2 | [ req ] 3 | prompt = no 4 | distinguished_name = req_distinguished_name 5 | x509_extensions = root_ext # The extentions to add to the self signed cert 6 | string_mask = utf8only # This sets a mask for permitted string types 7 | 8 | 9 | # Subject of the root CA 10 | [ req_distinguished_name ] 11 | O = Example root CA 12 | OU = Example root CA 13 | # emailAddress = rootca@rootca.example 14 | CN = Example root CA 15 | 16 | 17 | # extensions added to the root CA self-signed certificate 18 | [ root_ext ] 19 | subjectKeyIdentifier = hash 20 | authorityKeyIdentifier = keyid:always,issuer 21 | basicConstraints = critical, CA:true 22 | 23 | 24 | # extensions to be added to the signed intermediate cert 25 | [ intermediate_ext ] 26 | subjectKeyIdentifier = hash 27 | authorityKeyIdentifier = keyid:always,issuer 28 | basicConstraints = critical, CA:true, pathlen:0 29 | keyUsage = critical, cRLSign, keyCertSign 30 | -------------------------------------------------------------------------------- /certgen/ssl-confs/server.cnf: -------------------------------------------------------------------------------- 1 | # https://wiki.openssl.org/index.php/Manual:Req(1) 2 | [ req ] 3 | prompt = no 4 | distinguished_name = req_distinguished_name 5 | req_extensions = req_ext # The extensions to add to a certificate request 6 | string_mask = utf8only # This sets a mask for permitted string types 7 | 8 | 9 | # Subject of the server certificate 10 | [ req_distinguished_name ] 11 | O = Example server 12 | OU = Example server 13 | # emailAddress = server@server.example 14 | #CN = server.example 15 | CN = localhost 16 | 17 | 18 | # Fields added to the server certificate 19 | [ req_ext ] 20 | subjectAltName = @alt_names 21 | 22 | 23 | # alternative names (domains) for the server 24 | [ alt_names ] 25 | #DNS.1 = server.example 26 | #DNS.2 = www.server.example 27 | DNS.1 = localhost 28 | DNS.2 = localhost.localdomain 29 | DNS.3 = localhost4 30 | DNS.4 = localhost4.localdomain4 31 | DNS.5 = localhost6 32 | DNS.6 = localhost6.localdomain6 33 | DNS.7 = 127.0.0.1.xip.io 34 | DNS.8 = *.127.0.0.1.xip.io 35 | DNS.9 = 127.0.0.1.nip.io 36 | DNS.10 = *.127.0.0.1.nip.io 37 | DNS.11 = lvh.me 38 | DNS.12 = *.lvh.me 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018, 2020 ssl-tests authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /certgen/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Zdeněk Žamberský 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | OPENSSL = openssl 22 | KEYTOOL = keytool 23 | JAVA = java 24 | JAVAC = javac 25 | 26 | CERTGEN_DIR = . 27 | CERTGEN_BUILD_DIR = build 28 | 29 | all: certgen_all 30 | 31 | clean: 32 | rm -rf $(CERTGEN_BUILD_DIR) 33 | 34 | include $(CERTGEN_DIR)/certgen.mk 35 | -------------------------------------------------------------------------------- /ssl-tests/src/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2020 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | public class Main { 26 | 27 | public static void main(String[] args) throws Exception { 28 | SSLSocketTester tester = new SSLSocketTester(); 29 | tester.init(); 30 | tester.testProviders(); 31 | if (tester.failed) { 32 | System.exit(1); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ssl-tests/src/KeystoreUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2020 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.FileInputStream; 26 | import java.security.KeyStore; 27 | 28 | public class KeystoreUtil { 29 | 30 | KeyStore loadKeystore(String file, String password) throws Exception { 31 | String defaultType = KeyStore.getDefaultType(); 32 | KeyStore keystore = KeyStore.getInstance(defaultType); 33 | try(FileInputStream fis = new FileInputStream(file)){ 34 | keystore.load(fis, file.toCharArray()); 35 | } 36 | return keystore; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /SSLContextInfo/src/SSLContextInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Zdeněk Žamberský 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | import java.security.NoSuchAlgorithmException; 24 | import java.security.Provider; 25 | import java.security.Security; 26 | import java.util.Arrays; 27 | import java.util.Set; 28 | import javax.net.ssl.SSLContext; 29 | 30 | public class SSLContextInfo { 31 | 32 | public static void main(String[] args) throws NoSuchAlgorithmException { 33 | Provider[] providers = Security.getProviders(); 34 | for (Provider provider : providers) { 35 | Set services = provider.getServices(); 36 | for (Provider.Service service : services) { 37 | 38 | String type = service.getType(); 39 | if (type.equals("SSLContext")) { 40 | System.out.println(provider.getName() + ": " + service.getAlgorithm()); 41 | SSLContext context = SSLContext.getInstance(service.getAlgorithm(), provider); 42 | } 43 | } 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## General info 2 | This project consists of: 3 | - ssl-tests - does SSL/TLS testing, see lower 4 | - certgen - generates keys/certificates/keystores (required by SSLSocketTest) 5 | - SSLContextInfo - lists available SSLContexts 6 | - SSLSocketInfo - lists default/supported ciphers for SSLSocket/SSLServerSocket (default SSLContext). 7 | 8 | To use specific JDK use JAVA_HOME env. variable: 9 | ``` 10 | export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk 11 | ``` 12 | 13 | ## ssl-tests 14 | It iterates over all providers/algorithm/protocol/cipher combinations and tests them one by one. 15 | It creates basic client+server scenario, where server just echos (repeats) everything client sends. 16 | Both server and client sockets are configured to have only one protocol and one cipher enabled at a time (these ones to be tested). 17 | Test then checks that no exeptions are thrown and that data sent and received match. 18 | 19 | run by: 20 | ``` 21 | make ssl-tests 22 | ``` 23 | 24 | #### makefile variables: 25 | - SSLTESTS_IGNORE_PROTOCOLS=... - protocols matching this pattern will be ignored 26 | - SSLTESTS_IGNORE_CIPHERS=... - ciphers matching this pattern will be ignored 27 | - SSLTESTS_SSL_CONFIG_FILTER=?,?,?,? - only specified combination of provider,algorithm,protocol,cipher will be tested 28 | - SSLTESTS_USE_OPENSSL_CLIENT=1 - use openssl client instead of default SSLSocketClient written in java for testing 29 | - SSLTESTS_USE_GNUTLS_CLIENT=1 - use gnutls client instead of default SSLSocketClient written in java for testing 30 | - SSLTESTS_USE_NSS_CLIENT=1 - use nss client instead of default SSLSocketClient written in java for testing 31 | 32 | #### IGNORED combinations: 33 | Currently, tested combination may show up as IGNORED for following reasons: 34 | - SSLv2Hello protocol is used, having this enabled as only protocol does not make sense as far as I know 35 | - [TLS_EMPTY_RENEGOTIATION_INFO_SCSV](https://tools.ietf.org/html/rfc5746#section-3.3) cipher is used, as this in not really a ciper 36 | - ["No appropriate protocol" exception](https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/ce1f37506608/src/share/classes/sun/security/ssl/Handshaker.java#l554) is thrown, as it is caused by invalid protocol/algorithm combination (thrown by handshaker) 37 | - protocol starts with DTLS - tests currently does not support DTLS 38 | - ciphers starting with TLS_KRB5 - tests currently does not support these 39 | - it is explicitly ignored (see higher) 40 | 41 | ## Other utilities 42 | 43 | run by: 44 | ``` 45 | make SSLContextInfo 46 | make SSLSocketInfo 47 | ``` 48 | -------------------------------------------------------------------------------- /certgen/test/certgen-test.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Zdeněk Žamberský 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | # requires following to be set 22 | # CERTGEN_TEST_DIR - directory with this file 23 | # CERTGEN_TEST_BUILD_DIR - directory, where to place build products 24 | # JAVA - java executable 25 | # JAVAC - javac executable 26 | 27 | CERTGEN_TEST_SRC_DIR = $(CERTGEN_TEST_DIR)/src 28 | 29 | CERTGEN_TEST_CLASSES_DIR = $(CERTGEN_TEST_BUILD_DIR)/classes 30 | CERTGEN_TEST_MAIN_CLASS = TestSSL 31 | 32 | .PHONY: certgen_test_clean certgen_test_run 33 | 34 | certgen_test_clean: 35 | rm -rf $(CERTGEN_TEST_CLASSES_DIR) 36 | 37 | $(CERTGEN_TEST_BUILD_DIR): | $(CERTGEN_BUILD_DIR) 38 | mkdir $(CERTGEN_TEST_BUILD_DIR) 39 | 40 | $(CERTGEN_TEST_CLASSES_DIR): | $(CERTGEN_TEST_BUILD_DIR) 41 | mkdir $(CERTGEN_TEST_CLASSES_DIR) 42 | $(JAVAC) -encoding UTF-8 -d $(CERTGEN_TEST_CLASSES_DIR) \ 43 | $(CERTGEN_TEST_SRC_DIR)/$(CERTGEN_TEST_MAIN_CLASS).java 44 | 45 | # test app should return non-zero value without keystore + truststore config 46 | # and zero when correct keystore + truststore is set 47 | certgen_test_run: $(CERTGEN_TEST_CLASSES_DIR) $(KEYSTORE_JKS) $(TRUSTSTORE_JKS) 48 | ! $(JAVA) -cp $(CERTGEN_TEST_CLASSES_DIR) \ 49 | $(CERTGEN_TEST_MAIN_CLASS) &> /dev/null 50 | $(JAVA) -cp $(CERTGEN_TEST_CLASSES_DIR) \ 51 | -Djavax.net.ssl.keyStore=$(KEYSTORE_JKS) \ 52 | -Djavax.net.ssl.keyStorePassword=$(KEYSTORE_PASSWORD) \ 53 | -Djavax.net.ssl.trustStore=$(TRUSTSTORE_JKS) \ 54 | -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) \ 55 | $(CERTGEN_TEST_MAIN_CLASS) 56 | -------------------------------------------------------------------------------- /ssl-tests/src/StreamReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2021 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.InputStreamReader; 28 | import java.io.BufferedReader; 29 | import java.io.PrintStream; 30 | import java.util.List; 31 | import java.util.ArrayList; 32 | import java.util.logging.Level; 33 | import java.util.logging.Logger; 34 | 35 | public class StreamReader { 36 | 37 | InputStream is; 38 | List lines; 39 | Thread t; 40 | 41 | public StreamReader(InputStream is) { 42 | this.is = is; 43 | lines = new ArrayList(); 44 | t = new Thread(new Runnable() { 45 | public void run() { 46 | try { 47 | readAll(); 48 | } catch (Exception ex) { 49 | Logger.getLogger(StreamReader.class.getName()) 50 | .log(Level.SEVERE, null, ex); 51 | } 52 | } 53 | }); 54 | } 55 | 56 | private void readAll() throws IOException { 57 | try (InputStream is = this.is; 58 | InputStreamReader isr = new InputStreamReader(is); 59 | BufferedReader br = new BufferedReader(isr)) { 60 | String line = null; 61 | while ((line = br.readLine()) != null) { 62 | lines.add(line); 63 | } 64 | } 65 | } 66 | 67 | public void start() { 68 | t.start(); 69 | } 70 | 71 | public void waitFor() throws InterruptedException { 72 | t.join(); 73 | } 74 | 75 | public void printWithPrefix(PrintStream ps, String prefix) { 76 | for (String line: lines) { 77 | ps.println(prefix + line); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SSLSocketInfo/src/SSLSocketInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Zdeněk Žamberský 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | import java.net.Socket; 24 | import javax.net.ssl.SSLSocket; 25 | import javax.net.ssl.SSLSocketFactory; 26 | import java.net.ServerSocket; 27 | import javax.net.ssl.SSLServerSocket; 28 | import javax.net.ssl.SSLServerSocketFactory; 29 | import java.io.IOException; 30 | import java.util.Arrays; 31 | 32 | public class SSLSocketInfo { 33 | 34 | public static void printInfo(String name, String[] values) { 35 | System.out.println(" " + name); 36 | for(String value : values) { 37 | System.out.println(" " + value); 38 | } 39 | } 40 | 41 | public static void main(String[] args) { 42 | System.out.println("SSLSocket:"); 43 | SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 44 | try (Socket socket = socketFactory.createSocket()) { 45 | SSLSocket sslSocket = (SSLSocket) socket; 46 | printInfo("SupportedProtocols", sslSocket.getSupportedProtocols()); 47 | printInfo("SupportedCipherSuites", sslSocket.getSupportedCipherSuites()); 48 | 49 | printInfo("DefaultProtocols", sslSocket.getEnabledProtocols()); 50 | printInfo("DefaultCipherSuites", sslSocket.getEnabledCipherSuites()); 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | } 54 | System.out.println(); 55 | System.out.println("SSLServerSocket:"); 56 | SSLServerSocketFactory serverSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 57 | try (ServerSocket serverSocket = serverSocketFactory.createServerSocket()) { 58 | SSLServerSocket sslServerSocket = (SSLServerSocket) serverSocket; 59 | printInfo("SupportedProtocols", sslServerSocket.getSupportedProtocols()); 60 | printInfo("SupportedCipherSuites", sslServerSocket.getSupportedCipherSuites()); 61 | 62 | printInfo("DefaultProtocols", sslServerSocket.getEnabledProtocols()); 63 | printInfo("DefaultCipherSuites", sslServerSocket.getEnabledCipherSuites()); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /ssl-tests/ssl-tests.mk: -------------------------------------------------------------------------------- 1 | SSLTESTS_SRC_DIR = $(SSLTESTS_DIR)/src 2 | SSLTESTS_MAIN_CLASS = Main 3 | 4 | SSLTESTS_IGNORE_PROTOCOLS ?= $(shell \ 5 | if [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then \ 6 | if ! [ 1 = "$(JAVA_CONF_FIPS)" ] || ! [ 1 = "$(FIPS_MODE_ENABLED)" ] ; then \ 7 | printf '%s' 'TLSv1|TLSv1.1|TLSv1.3' ; \ 8 | elif [ 1 = "$(SSLTESTS_USE_OPENSSL_CLIENT)" ] || [ 1 = "$(SSLTESTS_USE_GNUTLS_CLIENT)" ] || [ 1 = "$(SSLTESTS_USE_NSS_CLIENT)" ] ; then \ 9 | printf '%s' 'TLSv1.2' ; \ 10 | fi ; \ 11 | else \ 12 | if grep -q "Red Hat Enterprise Linux Server release 7" /etc/redhat-release \ 13 | && [ "aarch64" = "$$( uname -m )" ] ; then \ 14 | printf '%s' 'TLSv1.3' ; \ 15 | fi ; \ 16 | fi ; \ 17 | ) 18 | SSLTESTS_IGNORE_CIPHERS ?= $(shell \ 19 | if [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then \ 20 | if ! [ 1 = "$(JAVA_CONF_FIPS)" ] || ! [ 1 = "$(FIPS_MODE_ENABLED)" ] ; then \ 21 | if [ "$(JAVA_VERSION_MAJOR)" -ge 16 ] ; then \ 22 | printf '%s' 'SSL_.*|TLS_DHE_DSS_.*|TLS_ECDHE_.*' ; \ 23 | else \ 24 | printf '%s' 'SSL_.*|TLS_DHE_DSS_.*' ; \ 25 | fi ; \ 26 | fi ; \ 27 | fi ; \ 28 | ) 29 | 30 | SSLTESTS_ONLY_SSL_DEFAULTS_PARAM := $(shell if [ 1 = "$(SSLTESTS_ONLY_SSL_DEFAULTS)" ] ; then printf '%s' '-Dssltests.onlyssldefaults=1' ; fi ) 31 | SSLTESTS_SSL_CONFIG_FILTER_PARAM := $(shell if [ -n "$(SSLTESTS_SSL_CONFIG_FILTER)" ] ; then printf '%s='%s'' '-Dssltests.sslconfigFilter' '$(SSLTESTS_SSL_CONFIG_FILTER)' ; fi ) 32 | SSLTESTS_IGNORE_PROTOCOLS_PARAM := $(shell if [ -n "$(SSLTESTS_IGNORE_PROTOCOLS)" ] ; then printf "%s='%s'" '-Dssltests.ignoredProtocolsPattern' '$(SSLTESTS_IGNORE_PROTOCOLS)' ; fi ) 33 | SSLTESTS_IGNORE_CIPHERS_PARAM := $(shell if [ -n "$(SSLTESTS_IGNORE_CIPHERS)" ] ; then printf "%s='%s'" '-Dssltests.ignoredCiphersPattern' '$(SSLTESTS_IGNORE_CIPHERS)' ; fi ) 34 | SSLTESTS_USE_OPENSSL_CLIENT_PARAM := $(shell if [ 1 = "$(SSLTESTS_USE_OPENSSL_CLIENT)" ] ; then printf '%s' '-Dssltests.cafile=$(ROOT_CRT) -Dssltests.useOpensslClient=1' ; fi ) 35 | SSLTESTS_USE_GNUTLS_CLIENT_PARAM := $(shell if [ 1 = "$(SSLTESTS_USE_GNUTLS_CLIENT)" ] ; then printf '%s' '-Dssltests.cafile=$(ROOT_CRT) -Dssltests.useGnutlsClient=1' ; fi ) 36 | SSLTESTS_USE_NSS_CLIENT_PARAM := $(shell if [ 1 = "$(SSLTESTS_USE_NSS_CLIENT)" ] ; then printf '%s' '-Dssltests.nssdbDir=$(NSSDB_CLIENT_DIR) -Dssltests.useNssClient=1' ; fi ) 37 | SSLTESTS_NSSDB_DEP := $(shell if [ 1 = "$(SSLTESTS_USE_NSS_CLIENT)" ] ; then printf '%s' '$(NSSDB_CLIENT_DIR)' ; fi ) 38 | SSLTESTS_SERVER_SHUTDOWN_OUTPUT_PARAM := $(shell if [ -n "$(SSLTESTS_SERVER_SHUTDOWN_OUTPUT)" ] ; then printf "%s" '-Dssltests.serverShutdownOutput=1' ; fi ) 39 | 40 | .PHONY: ssl-tests ssl-tests-clean ssl-tests-build ssl-tests-run 41 | 42 | ssl-tests: ssl-tests-run 43 | 44 | ssl-tests-clean: 45 | rm -rf $(SSLTESTS_CLASSES_DIR) 46 | 47 | ssl-tests-build: $(SSLTESTS_CLASSES_DIR) 48 | 49 | ssl-tests-run: $(SSLTESTS_CLASSES_DIR) $(JAVA_SECURITY_DEPS) $(SSLTESTS_NSSDB_DEP) 50 | if $(JAVAC) -version 2>&1 | grep " 11" ; then \ 51 | exports=""; \ 52 | elif $(JAVAC) -version 2>&1 | grep " 1.8.0" ; then \ 53 | exports=""; \ 54 | else \ 55 | exports="--add-exports java.base/sun.security.internal.spec=ALL-UNNAMED"; \ 56 | fi ;\ 57 | $(JAVA) -cp "$<$(JAVA_CP_APPEND)" \ 58 | $$exports \ 59 | $(JAVA_SECURITY_PARAMS) \ 60 | $(SSLTESTS_ONLY_SSL_DEFAULTS_PARAM) $(SSLTESTS_SSL_CONFIG_FILTER_PARAM) $(SSLTESTS_IGNORE_PROTOCOLS_PARAM) $(SSLTESTS_IGNORE_CIPHERS_PARAM) $(SSLTESTS_USE_OPENSSL_CLIENT_PARAM) $(SSLTESTS_USE_GNUTLS_CLIENT_PARAM) $(SSLTESTS_USE_NSS_CLIENT_PARAM) $(SSLTESTS_SERVER_SHUTDOWN_OUTPUT_PARAM) \ 61 | $(SSLTESTS_CUSTOM_JAVA_PARAMS) \ 62 | $(SSLTESTS_MAIN_CLASS) 63 | 64 | 65 | $(SSLTESTS_CLASSES_DIR): $(SSLTESTS_SRC_DIR) 66 | mkdir -p $@ 67 | $(JAVAC) -encoding UTF-8 -g -d $@ $ lines = ExternalClient.getCommandOutput(toolsPrefix + "listsuites"); 68 | boolean cipherFound = false; 69 | String cipher = null; 70 | String cipherProtocol; 71 | String additionalLine; 72 | 73 | for (String line : lines) { 74 | line = line.trim(); 75 | if (!cipherFound) { 76 | if (line.startsWith("TLS_")) { 77 | // remove traling : 78 | cipher = line.replaceAll(":$", ""); 79 | cipherFound = true; 80 | } 81 | continue; 82 | } 83 | cipherFound = false; 84 | additionalLine = line; 85 | if (additionalLine.indexOf("Enabled") < 0) { 86 | continue; 87 | } 88 | cipherProtocol = null; 89 | if (additionalLine.indexOf("TLS 1.3") >= 0) { 90 | cipherProtocol = "TLSv1.3"; 91 | } 92 | if (!testCompatible(protocol, cipher, cipherProtocol)) { 93 | continue; 94 | } 95 | hs.add(cipher); 96 | } 97 | return hs; 98 | } 99 | 100 | public ProcessBuilder getClientProcessBuilder(String host, int port, String cafile, String logfile) { 101 | return new ProcessBuilder(toolsPrefix + "tstclnt", "-4", "-d", nssdbDir, "-h", host, "-p", String.valueOf(port), "-Q"); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ############################################################################################### 4 | # bash run.sh jdk [bug] 5 | # bash run.sh jdk [dir] 6 | # to run without jtreg (without this wrapper), it should be enough to use main makefile 7 | ################################################################################################ 8 | 9 | SCRIPT_SOURCE="${BASH_SOURCE[0]}" 10 | while [ -h "$SCRIPT_SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink 11 | SCRIPT_DIR="$( cd -P "$( dirname "$SCRIPT_SOURCE" )" && pwd )" 12 | SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")" 13 | # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located 14 | [[ $SCRIPT_SOURCE != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE" 15 | done 16 | readonly SCRIPT_DIR="$( cd -P "$( dirname "$SCRIPT_SOURCE" )" && pwd )" 17 | 18 | pushd ${SCRIPT_DIR} 19 | 20 | OS=`uname -s` 21 | CYGWIN="false" 22 | case "$OS" in 23 | Windows_* | CYGWIN_NT* ) 24 | PS=";" 25 | FS="\\" 26 | CYGWIN="true" 27 | ;; 28 | * ) 29 | echo "Non cygwin system!" 30 | ;; 31 | esac 32 | 33 | READLINK_F="-f" 34 | readlink $READLINK_F "." || READLINK_F="" 35 | 36 | envVarArg="-e:CUSTOM_DUMMY_VARIABLE=true,JAVA_TOOL_OPTIONS,OTOOL_BUILD_ARCH,DISPLAY" 37 | keys=$(env | grep OTOOL_ | sed "s/=.*//") 38 | for key in $keys; do 39 | envVarArg="$envVarArg,$key" 40 | done 41 | 42 | set -e 43 | set -o pipefail 44 | 45 | JAVA="${1}" 46 | if [ "x$JAVA" == "x" ] ; then 47 | echo "Jdk is mandatory param (bugid is optional)" 48 | exit 1 49 | fi 50 | 51 | if [ "x$CYGWIN" == "xtrue" ] ; then 52 | JAVA="$(cygpath -aw "${JAVA}")" 53 | fi 54 | 55 | if [ "x$JAVA_HOME" == "x" ] ; then 56 | JAVA_HOME="$(dirname $(dirname $(readlink $READLINK_F $(which javac))))" 57 | fi 58 | 59 | if [ "x$CYGWIN" == "xtrue" ] ; then 60 | JAVA_HOME="$(cygpath -aw "${JAVA_HOME}")" 61 | fi 62 | 63 | TIME=$(date +%s) 64 | BUGID="${2}" 65 | 66 | FOLDER="${SCRIPT_DIR}/jtreg-wrappers" 67 | if [ "x$CYGWIN" == "xtrue" ] ; then 68 | FOLDER="$(cygpath -aw "${FOLDER}")" 69 | fi 70 | if [ "x$BUGID" != "x" -a -e "$BUGID" ] ; then 71 | FOLDER="$BUGID" 72 | BUGID="" 73 | elif [ "x$BUGID" != "x" ]; then 74 | BUGID="-bug:$BUGID" 75 | fi 76 | 77 | if [ ! "x$FORCE_TMP_JTREG" == "x" ] ; then 78 | ddir=`mktemp -d` 79 | pushd "$ddir" 80 | ball=forcedJtreg.tar.gz 81 | curl -L -o "$ball" "$FORCE_TMP_JTREG" 82 | tar -xf "$ball" 83 | popd 84 | JTREG_HOME="$ddir/jtreg" 85 | fi 86 | 87 | if [ "x$JTREG_HOME" == "x" ] ; then 88 | JTREG_HOME="$SCRIPT_DIR/jtreg" 89 | else 90 | if [ ! -e "$JTREG_HOME/lib/jtreg.jar" ] ; then 91 | echo "You have jtreg home set, but it do not contain lib/jtreg.jar" 92 | exit 1 93 | fi 94 | fi 95 | 96 | if [ "x$JDK_MAJOR" == "x" ] ; then 97 | JDK_MAJOR=8 98 | if [[ -e "$JAVA/bin/jshell" || -e "$JAVA/bin/jshell.exe" ]] ; then 99 | jshellScript="$(mktemp)" 100 | printf "System.out.print(Runtime.version().major())\n/exit" > "${jshellScript}" 101 | if [ "x$CYGWIN" == "xtrue" ] ; then 102 | jshellScript="$(cygpath -aw "${jshellScript}")" 103 | fi 104 | JDK_MAJOR=$( "$JAVA/bin/jshell" "${jshellScript}" 2> /dev/null | grep -v -e "Started recording" -e "copy recording data to file" -e "^$" -e "\[" ) 105 | rm "${jshellScript}" 106 | fi 107 | fi 108 | echo "treating jdk as: $JDK_MAJOR" 109 | 110 | if [ ! -e "$JTREG_HOME" ] ; then 111 | if [ "0$JDK_MAJOR" -le "8" ] ; then 112 | ball=jtreg-6+2-jtrfix.tar.gz 113 | curl -L -o "$ball" "https://github.com/andrlos/jtreg/releases/download/6.2-jtrfix-V01.0/$ball" 114 | else 115 | ball=jtreg-7.3.1+2-jtrfix.tar.gz 116 | curl -L -o "$ball" "https://github.com/andrlos/jtreg/releases/download/7.3.1%2B2-jtrfix-V01.0/$ball" 117 | fi 118 | tar -xf $ball 119 | fi 120 | 121 | echo Running with $JAVA... 122 | 123 | 124 | JTREG_JAR="$JTREG_HOME/lib/jtreg.jar" 125 | if [ "x$CYGWIN" == "xtrue" ] ; then 126 | JTREG_JAR="$(cygpath -aw "${JTREG_JAR}")" 127 | fi 128 | 129 | jtWork="test.${TIME}/jdk/work" 130 | jtReport="test.${TIME}/jdk/report" 131 | 132 | r=0 133 | mkdir -p "${jtWork}" "${jtReport}" 134 | "${JAVA_HOME}/bin/java" -jar "$JTREG_JAR" -v1 -a -ignore:quiet \ 135 | -w:"${jtWork}" -r:"${jtReport}" \ 136 | -jdk:"$JAVA" \ 137 | -xml \ 138 | $BUGID \ 139 | $envVarArg \ 140 | $FOLDER | tee test.${TIME}/tests.log || r=$? 141 | 142 | tar -czf test.${TIME}.tar.gz "${jtWork}" "${jtReport}" || echo "Packing of results tarball failed" 143 | 144 | popd 145 | 146 | if [ ! `readlink $READLINK_F ${SCRIPT_DIR}` == `pwd` ] ; then 147 | mv ${SCRIPT_DIR}/test.${TIME} . 148 | mv -v ${SCRIPT_DIR}/test.${TIME}.tar.gz . || echo "Moving of results tarball failed" 149 | fi 150 | 151 | if ! [ -f test.${TIME}/tests.log ] ; then 152 | echo "Missing tests.log!" 1>&2 153 | exit 1 154 | fi 155 | 156 | # passes should be present in tests.log 157 | grep -Eqi '^passed:' test.${TIME}/tests.log || exit 1 158 | # check for failures/errors in tests.log 159 | ! grep -Eqi '^(failed|error):' test.${TIME}/tests.log || exit 1 160 | 161 | exit $r 162 | -------------------------------------------------------------------------------- /ssl-tests/src/SSLSocketClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2020 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | import java.net.InetSocketAddress; 29 | import java.nio.charset.StandardCharsets; 30 | import java.util.logging.Level; 31 | import java.util.logging.Logger; 32 | import javax.net.ssl.SSLSocket; 33 | import javax.net.ssl.SSLSocketFactory; 34 | 35 | public class SSLSocketClient { 36 | 37 | SSLSocketFactory sslSocketFactory; 38 | String[] protocols; 39 | String[] ciphers; 40 | static final byte[] dataBuffer; 41 | 42 | public static final int EOT = 0x4; 43 | 44 | static { 45 | StringBuilder sb = new StringBuilder(); 46 | for (int i = 0; i < 2000; ++i) { 47 | sb = sb.append("message").append(i).append("\n"); 48 | } 49 | sb.append((char) EOT); 50 | /* End of transmition */ 51 | dataBuffer = sb.toString().getBytes(StandardCharsets.UTF_8); 52 | } 53 | 54 | public SSLSocketClient(SSLSocketFactory sslSocketFactory, 55 | String[] protocols, 56 | String[] ciphers) { 57 | this.sslSocketFactory = sslSocketFactory; 58 | this.protocols = protocols; 59 | this.ciphers = ciphers; 60 | } 61 | 62 | public void test(String host, int port) throws IOException { 63 | 64 | try (SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket()) { 65 | 66 | sslSocket.setEnabledProtocols(protocols); 67 | sslSocket.setEnabledCipherSuites(ciphers); 68 | 69 | InetSocketAddress socketAddress = new InetSocketAddress(host, port); 70 | sslSocket.connect(socketAddress); 71 | // we want exceptions to be thrown early (before we start a sending thread, if possible) 72 | sslSocket.startHandshake(); 73 | 74 | Thread sendingThread = new Thread() { 75 | @Override 76 | public void run() { 77 | try { 78 | OutputStream os = sslSocket.getOutputStream(); 79 | int sent = 0; 80 | while (sent < dataBuffer.length) { 81 | os.write(dataBuffer[sent++]); 82 | } 83 | } catch (Exception ex) { 84 | if (!SSLSocketTester.isOkException(ex)) { 85 | Logger.getLogger(SSLSocketClient.class.getName()).log(Level.SEVERE, null, ex); 86 | try { 87 | sslSocket.close(); 88 | } catch (IOException ex2) { 89 | // ignored 90 | } 91 | } 92 | } 93 | } 94 | }; 95 | try { 96 | sendingThread.start(); 97 | InputStream is = sslSocket.getInputStream(); 98 | 99 | int read = 0; 100 | int readByte = 0; 101 | while ((readByte = is.read()) >= 0) { 102 | if (read > dataBuffer.length) { 103 | throw new RuntimeException("Received more data then sent!"); 104 | } 105 | if (readByte != (dataBuffer[read++] & 0xFF)) { 106 | throw new RuntimeException("Received different data then sent!"); 107 | } 108 | if (readByte == EOT) { 109 | break; 110 | } 111 | } 112 | if (read != dataBuffer.length) { 113 | throw new RuntimeException("Received less data then sent: " + read + " < " + dataBuffer.length + " !"); 114 | } 115 | } finally { 116 | try { 117 | sendingThread.join(); 118 | sendingThread = null; 119 | } catch (InterruptedException ex) { 120 | Logger.getLogger(SSLSocketClient.class.getName()).log(Level.SEVERE, null, ex); 121 | } 122 | } 123 | } 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /jtreg-wrappers/SysDepsProps.java: -------------------------------------------------------------------------------- 1 | import java.io.InputStream; 2 | import java.io.IOException; 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.nio.file.Files; 6 | import java.nio.file.FileSystems; 7 | import java.util.List; 8 | import java.util.ArrayList; 9 | import java.util.Map; 10 | import java.util.HashMap; 11 | import java.util.concurrent.Callable; 12 | 13 | public class SysDepsProps implements Callable> { 14 | 15 | Thread streamDiscarder(final InputStream is) { 16 | return new Thread() { 17 | @Override 18 | public void run() { 19 | try { 20 | while (is.read() >= 0) { /* discard */ }; 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | } finally { 24 | try { 25 | is.close(); 26 | } catch (IOException e) { 27 | e.printStackTrace(); 28 | } 29 | } 30 | } 31 | }; 32 | } 33 | 34 | Thread streamReader(final InputStream is, final List linesBuf) { 35 | if (linesBuf == null) { 36 | return streamDiscarder(is); 37 | } 38 | return new Thread() { 39 | @Override 40 | public void run() { 41 | try (InputStreamReader isr = new InputStreamReader(is); 42 | BufferedReader br = new BufferedReader(isr)){ 43 | String line; 44 | while ((line = br.readLine()) != null) { 45 | linesBuf.add(line); 46 | } 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } finally { 50 | try { 51 | is.close(); 52 | } catch (IOException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | } 57 | }; 58 | } 59 | 60 | boolean runCmd(String[] command, List stdoutBuf, List stderrBuf) { 61 | ProcessBuilder pb = new ProcessBuilder(command); 62 | Process p = null; 63 | Thread outReader = null; 64 | Thread errReader= null; 65 | int retVal = 0; 66 | try { 67 | p = pb.start(); // throws exception if program does not exist 68 | outReader = streamReader(p.getInputStream(), stdoutBuf); 69 | outReader.start(); 70 | errReader = streamReader(p.getErrorStream(), stderrBuf); 71 | errReader.start(); 72 | p.getOutputStream().close(); 73 | p.waitFor(); 74 | return true; 75 | } catch (Exception ex) { 76 | if (p != null) { 77 | p.destroy(); 78 | } 79 | } finally { 80 | try { 81 | if (outReader != null) { 82 | outReader.join(); 83 | } 84 | if (errReader != null) { 85 | errReader.join(); 86 | } 87 | } catch (InterruptedException ex) {} 88 | } 89 | return false; 90 | } 91 | 92 | boolean checkOnPath(String cmd) { 93 | return runCmd(new String[]{cmd, "--help"}, null, null); 94 | } 95 | 96 | boolean containsString(List list, String str) { 97 | for (String s : list) { 98 | if (s.contains(str)) { 99 | return true; 100 | } 101 | } 102 | return false; 103 | } 104 | 105 | boolean checkSupportsOption(String cmd, String option) { 106 | List stdoutBuf = new ArrayList(); 107 | List stderrBuf = new ArrayList(); 108 | if (!runCmd(new String[]{cmd, "--help"}, stdoutBuf, stderrBuf)) { 109 | return false; 110 | } 111 | return containsString(stdoutBuf, option) || containsString(stderrBuf, option); 112 | } 113 | 114 | boolean fileExists(String path) { 115 | return Files.exists(FileSystems.getDefault().getPath(path)); 116 | } 117 | 118 | String getTstclntCmd() { 119 | String cmd = "/usr/lib64/nss/unsupported-tools/tstclnt"; 120 | if (fileExists(cmd)) { 121 | return cmd; 122 | } 123 | cmd = "/usr/lib/nss/unsupported-tools/tstclnt"; 124 | if (fileExists(cmd)) { 125 | return cmd; 126 | } 127 | cmd = "tstclnt"; 128 | if (checkOnPath(cmd)) { 129 | return cmd; 130 | } 131 | return null; 132 | } 133 | 134 | boolean checkTstclnt() { 135 | String cmd = getTstclntCmd(); 136 | return cmd == null ? false : checkSupportsOption(cmd, "-Q"); 137 | } 138 | 139 | boolean checkGnutlsCli() { 140 | return checkOnPath("gnutls-cli"); 141 | } 142 | 143 | @Override 144 | public Map call() { 145 | Map map = new HashMap(); 146 | map.put("bin.gnutlscli", checkGnutlsCli() ? "true": "false"); 147 | map.put("bin.tstclnt", checkTstclnt() ? "true": "false"); 148 | return map; 149 | } 150 | 151 | public static void main(String[] args) { 152 | for (Map.Entry entry: new SysDepsProps().call().entrySet()) { 153 | System.out.println(entry.getKey() + ": " + entry.getValue()); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /certgen/test/src/TestSSL.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Zdeněk Žamberský 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | import javax.net.ssl.SSLServerSocketFactory; 24 | import javax.net.ServerSocketFactory; 25 | import javax.net.ssl.SSLSocketFactory; 26 | import javax.net.SocketFactory; 27 | import java.net.ServerSocket; 28 | import java.net.Socket; 29 | import java.net.InetSocketAddress; 30 | import java.net.InetAddress; 31 | import java.net.SocketException; 32 | import java.io.IOException; 33 | import java.io.OutputStream; 34 | import java.io.InputStream; 35 | 36 | public class TestSSL { 37 | 38 | public static void main(String[] args) throws Exception { 39 | Server server = new Server(); 40 | try { 41 | server.start(); 42 | int port = server.getPort(); 43 | SocketFactory sslSocketFactory = SSLSocketFactory.getDefault(); 44 | try(Socket socket = sslSocketFactory.createSocket()) { 45 | 46 | String hostname = "localhost"; 47 | InetSocketAddress inetSocketAddress = 48 | new InetSocketAddress(hostname, port); 49 | socket.connect(inetSocketAddress); 50 | try (OutputStream outputStream = socket.getOutputStream()) { 51 | // just doing connect is not enough to test SSLSocket works 52 | // send single byte to force it to do all handshakes etc... 53 | outputStream.write(1); 54 | outputStream.flush(); 55 | } 56 | } 57 | } finally { 58 | server.stop(); 59 | } 60 | } 61 | 62 | static class Server { 63 | 64 | private final Object lock = new Object(); 65 | ServerSocket serverSocket = null; 66 | Thread thread = null; 67 | int port = 0; 68 | 69 | public Server() { 70 | } 71 | 72 | public void start() throws IOException { 73 | synchronized (lock) { 74 | if (serverSocket == null) { 75 | ServerSocketFactory sslServerConnectionFactory = 76 | SSLServerSocketFactory.getDefault(); 77 | serverSocket = 78 | sslServerConnectionFactory.createServerSocket(); 79 | InetSocketAddress inetSocketAddress = 80 | new InetSocketAddress((InetAddress) null, 0); 81 | serverSocket.bind(inetSocketAddress); 82 | thread = new Thread(new Runnable() { 83 | public void run() { 84 | try { 85 | mainLoop(); 86 | } catch (SocketException ignored) { 87 | // this exception is expected 88 | // on serverSocket close 89 | } catch (IOException e) { 90 | e.printStackTrace(); 91 | } 92 | } 93 | }); 94 | thread.start(); 95 | port = serverSocket.getLocalPort(); 96 | } 97 | } 98 | } 99 | 100 | public void stop() throws IOException, InterruptedException { 101 | synchronized (lock) { 102 | if(serverSocket != null) { 103 | try { 104 | // closing socket makes server thread exit accept loop 105 | // with exception 106 | serverSocket.close(); 107 | } finally { 108 | thread.join(); 109 | serverSocket = null; 110 | port = 0; 111 | } 112 | } 113 | } 114 | } 115 | 116 | public int getPort() { 117 | return port; 118 | } 119 | 120 | 121 | private void mainLoop() throws IOException { 122 | for (;;) { 123 | // accept loop (until serverSocket is closed) 124 | try (Socket socket = serverSocket.accept()) { 125 | try (InputStream inputStream = socket.getInputStream()) { 126 | // just read and discard all received data 127 | // until connection is closed 128 | while(inputStream.read() >= 0); 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /ssl-tests/src/SSLSocketServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2020 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | import java.net.InetSocketAddress; 29 | import java.net.ServerSocket; 30 | import java.net.Socket; 31 | import java.net.SocketException; 32 | import java.util.logging.Level; 33 | import java.util.logging.Logger; 34 | import javax.net.ssl.SSLServerSocketFactory; 35 | import javax.net.ssl.SSLServerSocket; 36 | 37 | public class SSLSocketServer { 38 | 39 | final Object lock = new Object(); 40 | 41 | SSLServerSocketFactory serverSocketFactory; 42 | String[] protocols; 43 | String[] ciphers; 44 | 45 | SSLServerSocket serverSocket; 46 | Thread serverThread; 47 | String host = "localhost"; 48 | int port = 0; 49 | boolean shutdownOutput = false; 50 | 51 | public SSLSocketServer( 52 | SSLServerSocketFactory serverSocketFactory, 53 | String[] protocols, 54 | String[] ciphers) { 55 | this.ciphers = ciphers; 56 | this.protocols = protocols; 57 | this.serverSocketFactory = serverSocketFactory; 58 | } 59 | 60 | public void start() throws IOException { 61 | synchronized (lock) { 62 | if (serverSocket == null) { 63 | serverSocket 64 | = (SSLServerSocket) serverSocketFactory.createServerSocket(); 65 | serverSocket.setEnabledProtocols(protocols); 66 | serverSocket.setEnabledCipherSuites(ciphers); 67 | InetSocketAddress serverAddress 68 | = new InetSocketAddress(host, port); 69 | serverSocket.bind(serverAddress); 70 | port = serverSocket.getLocalPort(); 71 | Runnable runnable = new Runnable() { 72 | @Override 73 | public void run() { 74 | try { 75 | serverLoop(); 76 | } catch (SocketException ignored) { 77 | // this exception is expected 78 | // on serverSocket close 79 | } catch (Exception ex) { 80 | if (!SSLSocketTester.isOkException(ex)) { 81 | Logger.getLogger( 82 | SSLSocketServer.class.getName()) 83 | .log(Level.SEVERE, null, ex); 84 | } 85 | } 86 | } 87 | }; 88 | serverThread = new Thread(runnable); 89 | serverThread.start(); 90 | } 91 | } 92 | } 93 | 94 | public String getHost() { 95 | synchronized (lock) { 96 | return host; 97 | } 98 | } 99 | 100 | public int getPort() { 101 | synchronized (lock) { 102 | return port; 103 | } 104 | } 105 | 106 | public void stop() throws IOException { 107 | synchronized (lock) { 108 | if (serverSocket != null) { 109 | try { 110 | serverSocket.close(); 111 | } finally { 112 | try { 113 | if (serverThread != null) { 114 | serverThread.join(); 115 | } 116 | } catch (InterruptedException ex) { 117 | Logger.getLogger(SSLSocketServer.class.getName()).log(Level.SEVERE, null, ex); 118 | } 119 | port = 0; 120 | serverThread = null; 121 | serverSocket = null; 122 | } 123 | } 124 | } 125 | } 126 | 127 | public void serverLoop() throws IOException { 128 | for (;;) { 129 | try (Socket socket = serverSocket.accept()) { 130 | OutputStream os = socket.getOutputStream(); 131 | InputStream is = socket.getInputStream(); 132 | int readByte; 133 | while ((readByte = is.read()) >= 0) { 134 | os.write(readByte); 135 | } 136 | // see: https://bugzilla.redhat.com/show_bug.cgi?id=1918473 137 | if (shutdownOutput) { 138 | try { 139 | socket.shutdownOutput(); 140 | } catch (UnsupportedOperationException ex) { 141 | // ignored 142 | } 143 | } 144 | } 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /ssl-tests/src/GnutlsClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2021 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | import java.io.InputStreamReader; 29 | import java.io.BufferedReader; 30 | import java.io.PrintStream; 31 | import java.util.logging.Level; 32 | import java.util.logging.Logger; 33 | import java.util.Set; 34 | import java.util.HashSet; 35 | import java.util.List; 36 | import java.util.ArrayList; 37 | import java.nio.file.Files; 38 | import java.nio.file.Path; 39 | import java.nio.file.FileSystems; 40 | 41 | /* 42 | broken configs? 43 | make clean && make SSLTESTS_USE_OPENSSL_CLIENT=1 SSLTESTS_SSL_CONFIG_FILTER='SunJSSE,TLSv1.3,TLSv1.3,TLS_AES_256_GCM_SHA384' 44 | not supported by ojdk? 45 | make clean && make SSLTESTS_USE_OPENSSL_CLIENT=1 SSLTESTS_SSL_CONFIG_FILTER='SunJSSE,TLSv1.3,TLSv1.3,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' 46 | */ 47 | 48 | public class GnutlsClient extends ExternalClient { 49 | 50 | /* supported commandline params */ 51 | static boolean clientLogfile = false; 52 | 53 | static { 54 | try { 55 | checkFeatures(); 56 | } catch (Exception ex) { 57 | Logger.getLogger(OpensslClient.class.getName()).log(Level.SEVERE, null, ex); 58 | } 59 | } 60 | 61 | 62 | public GnutlsClient() { 63 | skipData = !clientLogfile; 64 | } 65 | 66 | public static void checkFeatures() throws Exception { 67 | List clientHelp = getCommandOutput("gnutls-cli", "--help"); 68 | for (String line: clientHelp) { 69 | if (line.trim().startsWith("--logfile")) { 70 | clientLogfile = true; 71 | } 72 | } 73 | } 74 | 75 | public static String getJavaProtoName(String gnuTlsProto) { 76 | switch (gnuTlsProto) { 77 | case "SSL3.0": 78 | return "SSLv3"; 79 | case "TLS1.0": 80 | return "TLSv1"; 81 | case "TLS1.1": 82 | return "TLSv1.1"; 83 | case "TLS1.2": 84 | return "TLSv1.2"; 85 | case "TLS1.3": 86 | return "TLSv1.3"; 87 | default: 88 | throw new IllegalArgumentException("Unknown protocol: " + gnuTlsProto); 89 | } 90 | } 91 | 92 | 93 | public static HashSet getSupportedCiphers(String protocol) throws Exception { 94 | HashSet hs = new HashSet(); 95 | String name; 96 | Path path = FileSystems.getDefault().getPath("/etc/crypto-policies/back-ends/gnutls.config"); 97 | if (Files.exists(path)) { 98 | name = "@SYSTEM"; 99 | } else { 100 | name = "NORMAL"; 101 | } 102 | List lines = ExternalClient.getCommandOutput("gnutls-cli", "--priority", name, "--list"); 103 | boolean cipherSuitesFound = false; 104 | String[] components; 105 | String cipherSuite; 106 | String cipherProto; 107 | 108 | for (String line : lines) { 109 | line = line.trim(); 110 | if (!cipherSuitesFound) { 111 | if (line.startsWith("Cipher suites")) { 112 | cipherSuitesFound = true; 113 | } 114 | continue; 115 | } 116 | if (line.length() == 0) { 117 | break; 118 | } 119 | if (line.startsWith("Certificate types")) { 120 | break; 121 | } 122 | components = line.split("\\s+"); 123 | if (components.length < 4) { 124 | break; 125 | } 126 | cipherSuite = components[0]; 127 | cipherProto = components[3]; 128 | cipherProto = getJavaProtoName(cipherProto); 129 | /* convert cipher suite names from gnutls format to IANA format */ 130 | cipherSuite = cipherSuite.replaceAll("^TLS_ECDHE_ECDSA_","TLS_ECDHE_ECDSA_WITH_"); 131 | cipherSuite = cipherSuite.replaceAll("^TLS_ECDHE_RSA_","TLS_ECDHE_RSA_WITH_"); 132 | cipherSuite = cipherSuite.replaceAll("^TLS_DHE_RSA_","TLS_DHE_RSA_WITH_"); 133 | cipherSuite = cipherSuite.replaceAll("^TLS_RSA_","TLS_RSA_WITH_"); 134 | cipherSuite = cipherSuite.replaceAll("_SHA1$","_SHA"); 135 | cipherSuite = cipherSuite.replaceAll("_POLY1305$", "_POLY1305_SHA256"); 136 | if (!testCompatible(protocol, cipherSuite, cipherProto)) { 137 | continue; 138 | } 139 | hs.add(cipherSuite); 140 | } 141 | return hs; 142 | } 143 | 144 | public ProcessBuilder getClientProcessBuilder(String host, int port, String cafile, String logfile) { 145 | if (clientLogfile) { 146 | return new ProcessBuilder("gnutls-cli", "--x509cafile=" + cafile, "--logfile=" + logfile, "--port=" + port, host); 147 | } else { 148 | return new ProcessBuilder("gnutls-cli", "--x509cafile", cafile, "--port", String.valueOf(port), host); 149 | } 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /ssl-tests/src/OpensslClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2021 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | import java.io.InputStreamReader; 29 | import java.io.BufferedReader; 30 | import java.io.PrintStream; 31 | import java.util.logging.Level; 32 | import java.util.logging.Logger; 33 | import java.util.Set; 34 | import java.util.HashSet; 35 | import java.util.List; 36 | import java.util.ArrayList; 37 | import java.nio.file.Files; 38 | import java.nio.file.Path; 39 | import java.nio.file.FileSystems; 40 | 41 | public class OpensslClient extends ExternalClient { 42 | 43 | String cafile; 44 | /* supported commandline params */ 45 | static boolean clientMsgfile = false; 46 | static boolean listStdName = false; 47 | static boolean listSupportedCiphers = false; 48 | static boolean listTls13 = false; 49 | 50 | static { 51 | try { 52 | checkFeatures(); 53 | } catch (Exception ex) { 54 | Logger.getLogger(OpensslClient.class.getName()).log(Level.SEVERE, null, ex); 55 | } 56 | } 57 | 58 | public OpensslClient() { 59 | cafile = System.getProperty("ssltests.cafile"); 60 | } 61 | 62 | public static void checkFeatures() throws Exception { 63 | List clientHelp = getCommandOutputAllIgnoreStatus("openssl", "s_client", "-help"); 64 | for (String line: clientHelp) { 65 | if (line.trim().startsWith("-msgfile")) { 66 | clientMsgfile = true; 67 | } 68 | } 69 | List ciphersHelp = getCommandOutputAllIgnoreStatus("openssl", "ciphers", "-help"); 70 | for (String line: ciphersHelp) { 71 | String line1 = line.trim(); 72 | if (line1.startsWith("-stdname")) { 73 | listStdName = true; 74 | } 75 | if (line1.startsWith("-s")) { 76 | listSupportedCiphers = true; 77 | } 78 | if (line1.startsWith("-tls1_3")) { 79 | listTls13 = true; 80 | } 81 | } 82 | } 83 | 84 | public static String convertCipherOpenssl(String cipher) { 85 | if (cipher.startsWith("AES")) { 86 | cipher = "TLS_RSA_WITH_" + cipher; 87 | } 88 | cipher = cipher.replace("ECDHE-ECDSA-", "TLS_ECDHE_ECDSA_WITH_"); 89 | cipher = cipher.replace("ECDHE-RSA-", "TLS_ECDHE_RSA_WITH_"); 90 | cipher = cipher.replace("DHE-RSA-", "TLS_DHE_RSA_WITH_"); 91 | cipher = cipher.replace("PSK-", "TLS_PSK_WITH_"); 92 | cipher = cipher.replace("DHE-PSK-", "TLS_DHE_PSK_WITH_"); 93 | cipher = cipher.replace("ECDHE-PSK-", "TLS_ECDHE_PSK_WITH_"); 94 | cipher = cipher.replace("AES128-SHA", "AES_128_CBC_SHA"); 95 | cipher = cipher.replace("AES256-SHA", "AES_256_CBC_SHA"); 96 | cipher = cipher.replace("AES128", "AES_128"); 97 | cipher = cipher.replace("AES256", "AES_256"); 98 | cipher = cipher.replace("-", "_"); 99 | return cipher; 100 | } 101 | 102 | 103 | public static HashSet getSupportedCiphers(String protocol) throws Exception { 104 | HashSet hs = new HashSet(); 105 | String protoOption; 106 | if (protocol.equals("SSLv2Hello")) { 107 | /* empty */ 108 | return hs; 109 | } else if (protocol.equals("SSLv3")) { 110 | protoOption="-ssl3"; 111 | } else if (protocol.equals("TLSv1")) { 112 | protoOption="-tls1"; 113 | } else if (protocol.startsWith("TLSv1.")) { 114 | protoOption="-tls1_" + protocol.substring(6); 115 | } else { 116 | throw new IllegalArgumentException("Invalid protocol " + protocol); 117 | } 118 | String name; 119 | Path path = FileSystems.getDefault().getPath("/etc/crypto-policies/back-ends/openssl.config"); 120 | Path path2 = FileSystems.getDefault().getPath("/etc/crypto-policies/back-ends/opensslcnf.config"); 121 | if (Files.exists(path) || Files.exists(path2)) { 122 | /* Ciphers enabled by current system crypto policy */ 123 | name="PROFILE=SYSTEM"; 124 | } else { 125 | name="DEFAULT"; 126 | } 127 | boolean fallback = (!listStdName || !listSupportedCiphers || !listTls13); 128 | ProcessBuilder pb; 129 | if (fallback) { 130 | pb = new ProcessBuilder("openssl", "ciphers", name); 131 | } else { 132 | pb = new ProcessBuilder("openssl", "ciphers", protoOption, "-s", "-stdname", name); 133 | } 134 | pb.redirectError(ProcessBuilder.Redirect.INHERIT); 135 | Process p = pb.start(); 136 | p.getOutputStream().close(); 137 | try (InputStream is = p.getInputStream(); 138 | InputStreamReader isr = new InputStreamReader(is); 139 | BufferedReader br = new BufferedReader(isr)) { 140 | String line = null; 141 | while ((line = br.readLine()) != null) { 142 | if (fallback) { 143 | String[] ciphers = line.split(":"); 144 | for (String cipher : ciphers) { 145 | String cipherConverted = convertCipherOpenssl(cipher); 146 | if (testCompatible(protocol, cipherConverted, null)) { 147 | hs.add(cipherConverted); 148 | } 149 | } 150 | } else { 151 | int spaceIndex = line.indexOf(" "); 152 | if (spaceIndex > 0) { 153 | line = line.substring(0, spaceIndex); 154 | } 155 | hs.add(line); 156 | } 157 | } 158 | } 159 | int retval = p.waitFor(); 160 | if (retval != 0) { 161 | throw new RuntimeException("Openssl ciphers exit value not zero: " + retval); 162 | } 163 | return hs; 164 | } 165 | 166 | public ProcessBuilder getClientProcessBuilder(String host, int port, String cafile, String msgFile) { 167 | if (clientMsgfile) { 168 | return new ProcessBuilder("openssl", "s_client", "-connect", host + ":" + port, "-servername", host, "-CAfile", cafile, "-msg", "-msgfile", msgFile.toString(), "-quiet", "-no_ign_eof"); 169 | } else { 170 | return new ProcessBuilder("openssl", "s_client", "-connect", host + ":" + port, "-servername", host, "-CAfile", cafile, "-quiet", "-no_ign_eof"); 171 | } 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /ssl-tests/src/ExternalClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2021 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | import java.io.InputStreamReader; 29 | import java.io.BufferedReader; 30 | import java.io.PrintStream; 31 | import java.util.logging.Level; 32 | import java.util.logging.Logger; 33 | import java.util.Set; 34 | import java.util.HashSet; 35 | import java.util.List; 36 | import java.util.ArrayList; 37 | import java.nio.file.Files; 38 | import java.nio.file.Path; 39 | import java.nio.file.FileSystems; 40 | 41 | public abstract class ExternalClient extends SSLSocketClient { 42 | 43 | String cafile; 44 | boolean skipData = false; 45 | 46 | public ExternalClient() { 47 | super(null, null, null); 48 | cafile = System.getProperty("ssltests.cafile"); 49 | } 50 | 51 | public static boolean testCompatible(String protocol, String cipherSuite, String cipherProtocol) { 52 | if (cipherProtocol == null) { 53 | if (cipherSuite.indexOf("_GCM_") >= 0 54 | || cipherSuite.indexOf("_CHACHA20_") >= 0 55 | || cipherSuite.indexOf("_SHA256") >= 0 56 | || cipherSuite.indexOf("_SHA384") >= 0) { 57 | if (cipherSuite.indexOf("_WITH_") >= 0) { 58 | cipherProtocol = "TLSv1.2"; 59 | } else { 60 | cipherProtocol = "TLSv1.3"; 61 | } 62 | } else { 63 | cipherProtocol = "TLSv1"; 64 | } 65 | } 66 | switch (protocol) { 67 | case "SSLv3": 68 | return cipherProtocol.equals("SSLv3"); 69 | case "TLSv1": 70 | return cipherProtocol.equals("TLSv1"); 71 | case "TLSv1.1": 72 | return cipherProtocol.equals("TLSv1.1") || cipherProtocol.equals("TLSv1"); 73 | case "TLSv1.2": 74 | return cipherProtocol.equals("TLSv1.2") || cipherProtocol.equals("TLSv1.1") || cipherProtocol.equals("TLSv1"); 75 | case "TLSv1.3": 76 | return cipherProtocol.equals("TLSv1.3"); 77 | default: 78 | throw new IllegalArgumentException("Unknown protocol: " + protocol); 79 | } 80 | } 81 | 82 | public static List getCommandOutput(boolean ignoreError, boolean bothOutputs, String... cmds) throws IOException { 83 | ProcessBuilder pb = new ProcessBuilder(cmds); 84 | StreamReader outReader = null; 85 | StreamReader errReader = null; 86 | Process p = null; 87 | int retval = 0; 88 | boolean error = false; 89 | try { 90 | p = pb.start(); 91 | outReader = new StreamReader(p.getInputStream()); 92 | errReader = new StreamReader(p.getErrorStream()); 93 | outReader.start(); 94 | errReader.start(); 95 | p.getOutputStream().close(); 96 | } catch (IOException ex) { 97 | if (p != null) { 98 | p.destroy(); 99 | } 100 | error = true; 101 | throw ex; 102 | } finally { 103 | if (p != null) { 104 | try { 105 | retval = p.waitFor(); 106 | if (!ignoreError && retval != 0) { 107 | error = true; 108 | } 109 | } catch (InterruptedException ex) { 110 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 111 | } 112 | } 113 | if (outReader != null) { 114 | try { 115 | outReader.waitFor(); 116 | } catch (InterruptedException ex) { 117 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 118 | } 119 | } 120 | if (errReader != null) { 121 | try { 122 | errReader.waitFor(); 123 | } catch (InterruptedException ex) { 124 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 125 | } 126 | if (error) { 127 | errReader.printWithPrefix(System.err, "stderr: "); 128 | } 129 | } 130 | } 131 | if (!ignoreError && retval != 0) { 132 | throw new RuntimeException("Program exit value not zero: " + retval); 133 | } 134 | if (bothOutputs) { 135 | List output = new ArrayList(); 136 | output.addAll(outReader.lines); 137 | output.addAll(errReader.lines); 138 | return output; 139 | } 140 | return outReader.lines; 141 | } 142 | 143 | public static List getCommandOutput(String... cmds) throws IOException { 144 | return getCommandOutput(false, false, cmds); 145 | } 146 | 147 | public static List getCommandOutputAllIgnoreStatus(String... cmds) throws IOException { 148 | return getCommandOutput(true, true, cmds); 149 | } 150 | 151 | public abstract ProcessBuilder getClientProcessBuilder(String host, int port, String cafile, String msgFile); 152 | 153 | 154 | public void test(String host, int port) throws IOException { 155 | Path logfile = Files.createTempFile("ssl-tests-openssl", null); 156 | ProcessBuilder pb = getClientProcessBuilder(host, port, cafile, logfile.toString()); 157 | int retval = 0; 158 | boolean error = false; 159 | Thread sendingThread = null; 160 | StreamReader errsr = null; 161 | StreamReader outsr = null; 162 | Process p = pb.start(); 163 | try { 164 | errsr = new StreamReader(p.getErrorStream()); 165 | errsr.start(); 166 | if (skipData) { 167 | outsr = new StreamReader(p.getInputStream()); 168 | outsr.start(); 169 | } else { 170 | sendingThread = new Thread() { 171 | @Override 172 | public void run() { 173 | OutputStream os = p.getOutputStream(); 174 | try { 175 | int sent = 0; 176 | while (sent < dataBuffer.length) { 177 | os.write(dataBuffer[sent++]); 178 | } 179 | os.flush(); 180 | } catch (Exception ex) { 181 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 182 | p.destroy(); 183 | } 184 | } 185 | }; 186 | 187 | sendingThread.start(); 188 | InputStream is = p.getInputStream(); 189 | 190 | int read = 0; 191 | int readByte = 0; 192 | while ((readByte = is.read()) >= 0) { 193 | if (read > dataBuffer.length) { 194 | throw new RuntimeException("Received more data then sent!"); 195 | } 196 | if (readByte != (dataBuffer[read++] & 0xFF)) { 197 | throw new RuntimeException("Received different data then sent!"); 198 | } 199 | if (readByte == EOT) { 200 | break; 201 | } 202 | } 203 | if (read != dataBuffer.length) { 204 | throw new RuntimeException("Received less data then sent: " + read + " < " + dataBuffer.length + " !"); 205 | } 206 | } 207 | } catch (IOException ex) { 208 | p.destroy(); 209 | error = true; 210 | throw ex; 211 | } finally { 212 | if (sendingThread != null) { 213 | try { 214 | sendingThread.join(); 215 | sendingThread = null; 216 | } catch (InterruptedException ex) { 217 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 218 | } 219 | } 220 | try { 221 | // sending thread is done, 222 | // close stdin -> client program should terminate afterwards 223 | p.getOutputStream().close(); 224 | } catch (Exception ex) { 225 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 226 | p.destroy(); 227 | } 228 | try { 229 | // wait for client program to terminate 230 | retval = p.waitFor(); 231 | if (retval != 0) { 232 | error = true; 233 | } 234 | } catch (InterruptedException ex) { 235 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 236 | } 237 | try { 238 | // close stdout 239 | if (skipData) { 240 | outsr.waitFor(); 241 | } else { 242 | p.getInputStream().close(); 243 | } 244 | } catch (Exception ex) { 245 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 246 | } 247 | if (errsr != null) { 248 | try { 249 | // wait for the stderr reader 250 | errsr.waitFor(); 251 | if (error) { 252 | errsr.printWithPrefix(System.err, "stderr: "); 253 | } 254 | errsr = null; 255 | } catch (InterruptedException ex) { 256 | Logger.getLogger(ExternalClient.class.getName()).log(Level.SEVERE, null, ex); 257 | } 258 | } 259 | if (error) { 260 | for (String line : Files.readAllLines(logfile)) { 261 | System.err.println("logfile: " + line); 262 | } 263 | } 264 | Files.deleteIfExists(logfile); 265 | } 266 | if (retval != 0) { 267 | throw new RuntimeException("Program exit value not zero: " + retval); 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /certgen/certgen.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, 2020 Zdeněk Žamberský 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | # requires following to be set 22 | # CERTGEN_DIR - directory with this file 23 | # CERTGEN_BUILD_DIR - directory, where to place build products 24 | # OPENSSL - openssl executable 25 | # KEYTOOL - keytool executable 26 | # + see test/certgen-test.gmk 27 | 28 | RSA_KEY_SIZE = 2048 29 | # DSA size needs to be 1024 to avoid: 30 | # java.security.InvalidKeyException: The security strength of SHA-1 digest algorithm is not sufficient for this key size 31 | DSA_KEY_SIZE = 1024 32 | CRT_DAYS = 365 33 | 34 | CERTGEN_CONFS_DIR = $(CERTGEN_DIR)/ssl-confs 35 | 36 | ROOT_KEY = $(CERTGEN_BUILD_DIR)/root.key 37 | ROOT_CRT = $(CERTGEN_BUILD_DIR)/root.crt 38 | ROOT_SRL = $(CERTGEN_BUILD_DIR)/root.srl 39 | ROOT_CNF = $(CERTGEN_CONFS_DIR)/root.cnf 40 | 41 | INTERMEDIATE_KEY = $(CERTGEN_BUILD_DIR)/intermediate.key 42 | INTERMEDIATE_CSR = $(CERTGEN_BUILD_DIR)/intermediate.csr 43 | INTERMEDIATE_CRT = $(CERTGEN_BUILD_DIR)/intermediate.crt 44 | INTERMEDIATE_SRL = $(CERTGEN_BUILD_DIR)/intermediate.srl 45 | INTERMEDIATE_CNF = $(CERTGEN_CONFS_DIR)/intermediate.cnf 46 | 47 | SERVER_KEY_RSA = $(CERTGEN_BUILD_DIR)/server-rsa.key 48 | SERVER_CSR_RSA = $(CERTGEN_BUILD_DIR)/server-rsa.csr 49 | SERVER_CRT_RSA = $(CERTGEN_BUILD_DIR)/server-rsa.crt 50 | SERVER_CNF_RSA = $(CERTGEN_CONFS_DIR)/server.cnf 51 | 52 | SERVER_KEY_EC = $(CERTGEN_BUILD_DIR)/server-ec.key 53 | SERVER_CSR_EC = $(CERTGEN_BUILD_DIR)/server-ec.csr 54 | SERVER_CRT_EC = $(CERTGEN_BUILD_DIR)/server-ec.crt 55 | SERVER_CNF_EC = $(CERTGEN_CONFS_DIR)/server.cnf 56 | 57 | SERVER_KEY_PARAM_DSA = $(CERTGEN_BUILD_DIR)/server-dsa.param 58 | SERVER_KEY_DSA = $(CERTGEN_BUILD_DIR)/server-dsa.key 59 | SERVER_CSR_DSA = $(CERTGEN_BUILD_DIR)/server-dsa.csr 60 | SERVER_CRT_DSA = $(CERTGEN_BUILD_DIR)/server-dsa.crt 61 | SERVER_CNF_DSA = $(CERTGEN_CONFS_DIR)/server.cnf 62 | 63 | CA_CHAIN_CRT = $(CERTGEN_BUILD_DIR)/cachain.crt 64 | KEYSORE_P12_RSA = $(CERTGEN_BUILD_DIR)/keystore-rsa.p12 65 | KEYSORE_P12_EC = $(CERTGEN_BUILD_DIR)/keystore-ec.p12 66 | KEYSORE_P12_DSA = $(CERTGEN_BUILD_DIR)/keystore-dsa.p12 67 | KEYSTORE_P12 = $(CERTGEN_BUILD_DIR)/keystore.p12 68 | KEYSTORE_JKS = $(CERTGEN_BUILD_DIR)/keystore.jks 69 | KEYSTORE_PASSWORD = changeit 70 | 71 | TRUSTSTORE_JKS = $(CERTGEN_BUILD_DIR)/truststore.jks 72 | TRUSTSTORE_P12 = $(CERTGEN_BUILD_DIR)/truststore.p12 73 | TRUSTSTORE_PASSWORD = changeit 74 | 75 | NSSDB_DIR = $(CERTGEN_BUILD_DIR)/nssdb 76 | NSSDB_PASSWORD = 77 | NSSDB_FIPS ?= 0 78 | 79 | NSSDB_CLIENT_DIR = $(CERTGEN_BUILD_DIR)/nssdb-client 80 | 81 | CERTGEN_TEST_DIR = $(CERTGEN_DIR)/test 82 | CERTGEN_TEST_BUILD_DIR = $(CERTGEN_BUILD_DIR)/test 83 | 84 | .PHONY: certgen_all certgen_clean 85 | 86 | certgen_all: $(KEYSTORE_JKS) $(TRUSTSTORE_JKS) certgen_test_run 87 | 88 | certgen_nssdb: $(NSSDB_DIR) 89 | 90 | certgen_clean: cleantest 91 | rm -rf $(ROOT_KEY) $(ROOT_CRT) $(ROOT_SRL) \ 92 | $(INTERMEDIATE_KEY) $(INTERMEDIATE_CSR) $(INTERMEDIATE_CRT) \ 93 | $(INTERMEDIATE_SRL) \ 94 | $(SERVER_KEY) $(SERVER_CSR) $(SERVER_CRT) \ 95 | $(CA_CHAIN_CRT) \ 96 | $(KEYSORE_P12) $(KEYSTORE_JKS) \ 97 | $(TRUSTSTORE_JKS) 98 | 99 | # create keys dir 100 | $(CERTGEN_BUILD_DIR): 101 | mkdir $(CERTGEN_BUILD_DIR) 102 | 103 | # generate root CA key 104 | $(ROOT_KEY): | $(CERTGEN_BUILD_DIR) 105 | $(OPENSSL) genrsa -out $(ROOT_KEY) $(RSA_KEY_SIZE) 106 | 107 | # generate root CA crt (self-signed) 108 | $(ROOT_CRT): $(ROOT_KEY) $(ROOT_CNF) 109 | $(OPENSSL) req -x509 -new -nodes -key $(ROOT_KEY) -days $(CRT_DAYS) \ 110 | -config $(ROOT_CNF) -out $(ROOT_CRT) 111 | 112 | 113 | # generate intermediate CA key 114 | $(INTERMEDIATE_KEY): | $(CERTGEN_BUILD_DIR) 115 | $(OPENSSL) genrsa -out $(INTERMEDIATE_KEY) $(RSA_KEY_SIZE) 116 | 117 | # generate intermediate CA csr (certificate signing request) 118 | $(INTERMEDIATE_CSR): $(INTERMEDIATE_KEY) $(INTERMEDIATE_CNF) 119 | $(OPENSSL) req -new -key $(INTERMEDIATE_KEY) \ 120 | -config $(INTERMEDIATE_CNF) -out $(INTERMEDIATE_CSR) 121 | 122 | # generate intermediate CA certificate, using csr, signed by root CA 123 | $(INTERMEDIATE_CRT): $(INTERMEDIATE_CSR) $(ROOT_CRT) $(ROOT_KEY) $(ROOT_CNF) 124 | $(OPENSSL) x509 -req -days $(CRT_DAYS) -in $(INTERMEDIATE_CSR) \ 125 | -CA $(ROOT_CRT) -CAkey $(ROOT_KEY) -CAserial $(ROOT_SRL) -CAcreateserial \ 126 | -extfile $(ROOT_CNF) -extensions intermediate_ext -out $(INTERMEDIATE_CRT) 127 | 128 | 129 | # generate server RSA key 130 | $(SERVER_KEY_RSA): | $(CERTGEN_BUILD_DIR) 131 | $(OPENSSL) genrsa -out $(SERVER_KEY_RSA) $(RSA_KEY_SIZE) 132 | 133 | # generate server RSA csr (certificate signing request) 134 | $(SERVER_CSR_RSA): $(SERVER_KEY_RSA) $(SERVER_CNF_RSA) 135 | $(OPENSSL) req -new -key $(SERVER_KEY_RSA) -config $(SERVER_CNF_RSA) \ 136 | -out $(SERVER_CSR_RSA) 137 | 138 | # generate server RSA certificate, using csr, signed by intermediate CA 139 | $(SERVER_CRT_RSA): $(SERVER_CSR_RSA) $(INTERMEDIATE_CRT) $(INTERMEDIATE_KEY) 140 | $(OPENSSL) x509 -req -days $(CRT_DAYS) -in $(SERVER_CSR_RSA) \ 141 | -CA $(INTERMEDIATE_CRT) -CAkey $(INTERMEDIATE_KEY) \ 142 | -CAserial $(INTERMEDIATE_SRL) -CAcreateserial \ 143 | -extfile $(INTERMEDIATE_CNF) -extensions server_ext -out $(SERVER_CRT_RSA) 144 | 145 | # generate server EC key 146 | $(SERVER_KEY_EC): | $(CERTGEN_BUILD_DIR) 147 | openssl ecparam -name prime256v1 -genkey -noout -out $(SERVER_KEY_EC) 148 | 149 | # generate server EC csr (certificate signing request) 150 | $(SERVER_CSR_EC): $(SERVER_KEY_EC) $(SERVER_CNF_EC) 151 | $(OPENSSL) req -new -key $(SERVER_KEY_EC) -config $(SERVER_CNF_EC) \ 152 | -out $(SERVER_CSR_EC) 153 | 154 | # generate server EC certificate, using csr, signed by intermediate CA 155 | $(SERVER_CRT_EC): $(SERVER_CSR_EC) $(INTERMEDIATE_CRT) $(INTERMEDIATE_KEY) 156 | $(OPENSSL) x509 -req -days $(CRT_DAYS) -in $(SERVER_CSR_EC) \ 157 | -CA $(INTERMEDIATE_CRT) -CAkey $(INTERMEDIATE_KEY) \ 158 | -CAserial $(INTERMEDIATE_SRL) -CAcreateserial \ 159 | -extfile $(INTERMEDIATE_CNF) -extensions server_ext -out $(SERVER_CRT_EC) 160 | 161 | # generate server DSA param (fallback to pregenerated, needed in FIPS mode) 162 | $(SERVER_KEY_PARAM_DSA): | $(CERTGEN_BUILD_DIR) 163 | # openssl dsaparam -out $(SERVER_KEY_PARAM_DSA) $(DSA_KEY_SIZE) 164 | cp $(CERTGEN_DIR)/server-dsa.param $(SERVER_KEY_PARAM_DSA) 165 | 166 | # generate server DSA key (fallback to pregenerated, needed in FIPS mode) 167 | $(SERVER_KEY_DSA): $(SERVER_KEY_PARAM_DSA) | $(CERTGEN_BUILD_DIR) 168 | openssl gendsa -out $(SERVER_KEY_DSA) $(SERVER_KEY_PARAM_DSA) \ 169 | || cp $(CERTGEN_DIR)/server-dsa.key $(SERVER_KEY_DSA) 170 | 171 | # generate server DSA csr (certificate signing request) 172 | $(SERVER_CSR_DSA): $(SERVER_KEY_DSA) $(SERVER_CNF_DSA) 173 | $(OPENSSL) req -new -key $(SERVER_KEY_DSA) -config $(SERVER_CNF_DSA) \ 174 | -out $(SERVER_CSR_DSA) 175 | 176 | # generate server DSA certificate, using csr, signed by intermediate CA 177 | $(SERVER_CRT_DSA): $(SERVER_CSR_DSA) $(INTERMEDIATE_CRT) $(INTERMEDIATE_KEY) 178 | $(OPENSSL) x509 -req -days $(CRT_DAYS) -in $(SERVER_CSR_DSA) \ 179 | -CA $(INTERMEDIATE_CRT) -CAkey $(INTERMEDIATE_KEY) \ 180 | -CAserial $(INTERMEDIATE_SRL) -CAcreateserial \ 181 | -extfile $(INTERMEDIATE_CNF) -extensions server_ext -out $(SERVER_CRT_DSA) 182 | 183 | 184 | # See: https://blogs.oracle.com/jtc/installing-trusted-certificates-into-a-java-keystore 185 | # concat CA certificates to the chain 186 | $(CA_CHAIN_CRT): $(ROOT_CRT) $(INTERMEDIATE_CRT) 187 | cat $(ROOT_CRT) $(INTERMEDIATE_CRT) > $(CA_CHAIN_CRT) 188 | 189 | # workaround to be able to generate pkcs12 keystore in fips 190 | # See: https://github.com/openssl/openssl/issues/20617 191 | OPENSSL_NOFIPS := $(shell if [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then printf 'OPENSSL_CONF=%s %s' "$(CERTGEN_CONFS_DIR)/empty.cfg" "$(OPENSSL)" ; else printf '%s' "$(OPENSSL)" ; fi ) 192 | 193 | # create keystore in PKCS12 format, which can then be imported to jks 194 | $(KEYSORE_P12_RSA): $(SERVER_CRT_RSA) $(SERVER_KEY_RSA) $(CA_CHAIN_CRT) 195 | $(OPENSSL_NOFIPS) pkcs12 -export -chain -in $(SERVER_CRT_RSA) -inkey $(SERVER_KEY_RSA) \ 196 | -name server-rsa -CAfile $(CA_CHAIN_CRT) -out $(KEYSORE_P12_RSA) \ 197 | -passout pass:$(KEYSTORE_PASSWORD) 198 | 199 | # create EC keystore in PKCS12 format, which can then be imported to jks 200 | $(KEYSORE_P12_EC): $(SERVER_CRT_EC) $(SERVER_KEY_EC) $(CA_CHAIN_CRT) 201 | $(OPENSSL_NOFIPS) pkcs12 -export -chain -in $(SERVER_CRT_EC) -inkey $(SERVER_KEY_EC) \ 202 | -name server-ec -CAfile $(CA_CHAIN_CRT) -out $(KEYSORE_P12_EC) \ 203 | -passout pass:$(KEYSTORE_PASSWORD) 204 | 205 | # create DSA keystore in PKCS12 format, which can then be imported to jks 206 | $(KEYSORE_P12_DSA): $(SERVER_CRT_DSA) $(SERVER_KEY_DSA) $(CA_CHAIN_CRT) 207 | $(OPENSSL) pkcs12 -export -chain -in $(SERVER_CRT_DSA) -inkey $(SERVER_KEY_DSA) \ 208 | -name server-dsa -CAfile $(CA_CHAIN_CRT) -out $(KEYSORE_P12_DSA) \ 209 | -passout pass:$(KEYSTORE_PASSWORD) 210 | 211 | # create p12 keystore 212 | KEYSTORE_P12_DSA_DEP := $(shell if ! [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then printf '%s' "$(KEYSORE_P12_DSA)" ; fi ) 213 | $(KEYSTORE_P12): $(KEYSORE_P12_RSA) $(KEYSORE_P12_EC) $(KEYSTORE_P12_DSA_DEP) 214 | $(KEYTOOL) $(KEYTOOL_PARAMS) -importkeystore \ 215 | -srckeystore $(KEYSORE_P12_RSA) -srcstoretype PKCS12 \ 216 | -srcstorepass $(KEYSTORE_PASSWORD) \ 217 | -destkeystore $(KEYSTORE_P12) -deststoretype PKCS12 \ 218 | -deststorepass $(KEYSTORE_PASSWORD) \ 219 | -noprompt -v 220 | $(KEYTOOL) $(KEYTOOL_PARAMS) -importkeystore \ 221 | -srckeystore $(KEYSORE_P12_EC) -srcstoretype PKCS12 \ 222 | -srcstorepass $(KEYSTORE_PASSWORD) \ 223 | -destkeystore $(KEYSTORE_P12) -deststoretype PKCS12 \ 224 | -deststorepass $(KEYSTORE_PASSWORD) \ 225 | -noprompt -v 226 | if ! [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then \ 227 | $(KEYTOOL) $(KEYTOOL_PARAMS) -importkeystore \ 228 | -srckeystore $(KEYSORE_P12_DSA) -srcstoretype PKCS12 \ 229 | -srcstorepass $(KEYSTORE_PASSWORD) \ 230 | -destkeystore $(KEYSTORE_P12) -deststoretype PKCS12 \ 231 | -deststorepass $(KEYSTORE_PASSWORD) \ 232 | -noprompt -v ; \ 233 | fi 234 | 235 | # create java keystore 236 | $(KEYSTORE_JKS): $(KEYSTORE_P12) 237 | $(KEYTOOL) $(KEYTOOL_PARAMS) -importkeystore \ 238 | -srckeystore $(KEYSTORE_P12) -srcstoretype PKCS12 \ 239 | -srcstorepass $(KEYSTORE_PASSWORD) \ 240 | -destkeystore $(KEYSTORE_JKS) -deststoretype JKS \ 241 | -deststorepass $(KEYSTORE_PASSWORD) \ 242 | -noprompt -v 243 | 244 | # create truststore with root CA cert 245 | $(TRUSTSTORE_P12): $(ROOT_CRT) 246 | $(KEYTOOL) $(KEYTOOL_PARAMS) -import -file $(ROOT_CRT) -alias rootca \ 247 | -keystore $(TRUSTSTORE_P12) -storetype PKCS12 -storepass $(TRUSTSTORE_PASSWORD) -noprompt 248 | 249 | # create truststore with root CA cert 250 | $(TRUSTSTORE_JKS): $(ROOT_CRT) 251 | $(KEYTOOL) $(KEYTOOL_PARAMS) -import -file $(ROOT_CRT) -alias rootca \ 252 | -keystore $(TRUSTSTORE_JKS) -storepass $(TRUSTSTORE_PASSWORD) -noprompt 253 | 254 | # create nss db with keys and certs 255 | $(NSSDB_DIR): $(ROOT_CRT) $(KEYSORE_P12_RSA) $(KEYSORE_P12_EC) # $(KEYSORE_P12_DSA) 256 | mkdir $(NSSDB_DIR) 257 | echo "$(NSSDB_PASSWORD)" > $(NSSDB_DIR)/password.txt 258 | certutil -N -d $(NSSDB_DIR) -f $(NSSDB_DIR)/password.txt 259 | touch $(NSSDB_DIR)/secmod.db 260 | certutil -A -n rootca -i $(ROOT_CRT) -t C,, -d $(NSSDB_DIR) -f $(NSSDB_DIR)/password.txt 261 | pk12util -i $(KEYSORE_P12_RSA) -W $(KEYSTORE_PASSWORD) -d $(NSSDB_DIR) -k $(NSSDB_DIR)/password.txt 262 | pk12util -i $(KEYSORE_P12_EC) -W $(KEYSTORE_PASSWORD) -d $(NSSDB_DIR) -k $(NSSDB_DIR)/password.txt 263 | # pk12util -i $(KEYSORE_P12_DSA) -W $(KEYSTORE_PASSWORD) -d $(NSSDB_DIR) -k $(NSSDB_DIR)/password.txt 264 | if [ 1 = $(NSSDB_FIPS) ] ; then \ 265 | printf '\n' | modutil -fips true -dbdir $(NSSDB_DIR) ; \ 266 | fi 267 | 268 | $(NSSDB_CLIENT_DIR): $(ROOT_CRT) 269 | mkdir $(NSSDB_CLIENT_DIR) 270 | echo "" > $(NSSDB_CLIENT_DIR)/password.txt 271 | certutil -N -d $(NSSDB_CLIENT_DIR) -f $(NSSDB_CLIENT_DIR)/password.txt 272 | certutil -A -n rootca -i $(ROOT_CRT) -t C,, -d $(NSSDB_CLIENT_DIR) -f $(NSSDB_CLIENT_DIR)/password.txt 273 | 274 | include $(CERTGEN_TEST_DIR)/certgen-test.mk 275 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: "test" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "*" 7 | push: 8 | branches: 9 | - "*" 10 | 11 | jobs: 12 | test-linux-jtreg: 13 | name: "Linux Jtreg" 14 | runs-on: "ubuntu-latest" 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | jdkconf: 19 | - JDK 8 20 | - JDK 11 21 | - JDK 17 22 | - JDK 21 23 | include: 24 | - jdkconf: JDK 8 25 | jdkver: "8" 26 | - jdkconf: JDK 11 27 | jdkver: "11" 28 | - jdkconf: JDK 17 29 | jdkver: "17" 30 | - jdkconf: JDK 21 31 | jdkver: "21" 32 | steps: 33 | - uses: actions/checkout@v3 34 | - name: "Install dependencies" 35 | run: | 36 | sudo apt-get update 37 | sudo apt-get install make openssl gnutls-bin libnss3 libnss3-tools libnss3-dev gcc pkg-config 38 | - name: Set up JDK 39 | uses: actions/setup-java@v3 40 | with: 41 | distribution: 'temurin' 42 | java-version: ${{ matrix.jdkver}} 43 | - name: Run 44 | run: ./run.sh "${JAVA_HOME}" 45 | - name: Upload results 46 | if: ${{ always() }} 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: "linux-jtreg-jdk${{ matrix.jdkver}}" 50 | path: "test.*.tar.gz" 51 | 52 | test-macos-jtreg: 53 | name: "MacOS Jtreg" 54 | runs-on: "macos-latest" 55 | strategy: 56 | fail-fast: false 57 | matrix: 58 | jdkconf: 59 | - JDK 11 60 | - JDK 17 61 | - JDK 21 62 | include: 63 | - jdkconf: JDK 11 64 | jdkver: "11" 65 | - jdkconf: JDK 17 66 | jdkver: "17" 67 | - jdkconf: JDK 21 68 | jdkver: "21" 69 | steps: 70 | - uses: actions/checkout@v3 71 | - name: Set up JDK 72 | uses: actions/setup-java@v3 73 | with: 74 | distribution: 'temurin' 75 | java-version: ${{ matrix.jdkver}} 76 | - name: Run 77 | run: ./run.sh "${JAVA_HOME}" 78 | - name: Upload results 79 | if: ${{ always() }} 80 | uses: actions/upload-artifact@v4 81 | with: 82 | name: "macos-jtreg-jdk${{ matrix.jdkver}}" 83 | path: "test.*.tar.gz" 84 | 85 | test-windows-cygwin-jtreg: 86 | name: "Windows-cygwin Jtreg" 87 | runs-on: "windows-latest" 88 | defaults: 89 | run: 90 | shell: C:\tools\cygwin\bin\bash.exe --login --norc -o igncr '{0}' 91 | strategy: 92 | fail-fast: false 93 | matrix: 94 | jdkconf: 95 | - JDK 8 96 | - JDK 11 97 | - JDK 17 98 | - JDK 21 99 | include: 100 | - jdkconf: JDK 8 101 | jdkver: "8" 102 | - jdkconf: JDK 11 103 | jdkver: "11" 104 | - jdkconf: JDK 17 105 | jdkver: "17" 106 | - jdkconf: JDK 21 107 | jdkver: "21" 108 | steps: 109 | - uses: actions/checkout@v3 110 | - name: Set up Cygwin 111 | uses: egor-tensin/setup-cygwin@v4 112 | with: 113 | packages: wget tar bash dos2unix make openssl gnutls-bin libnss3 libnss3-tools libnss3-dev gcc pkg-config 114 | - name: Set up JDK 115 | uses: actions/setup-java@v3 116 | with: 117 | distribution: 'temurin' 118 | java-version: ${{ matrix.jdkver}} 119 | - name: Run 120 | run: | 121 | set -ex 122 | cd "$GITHUB_WORKSPACE" ; pwd; ls -l 123 | echo "it seems default shell do not honour -o igncr nor --norc" 124 | dos2unix -v run.sh 125 | find . -type f -name "*.sh" -exec dos2unix -v {} \; 126 | bash.exe --login --norc -o igncr -c "cd \"$GITHUB_WORKSPACE\" && ./run.sh \"${JAVA_HOME}\"" 127 | - name: Upload results 128 | if: ${{ always() }} 129 | uses: actions/upload-artifact@v4 130 | with: 131 | name: "windows-cygwin-jdk${{ matrix.jdkver}}" 132 | path: "test.*.tar.gz" 133 | 134 | # test-windows-msys2-treg: 135 | # name: "Windows-msys2 Jtreg" 136 | # runs-on: "windows-latest" 137 | # strategy: 138 | # fail-fast: false 139 | # matrix: 140 | # jdkconf: 141 | # - JDK 8 142 | # - JDK 11 143 | # - JDK 17 144 | # - JDK 21 145 | # include: 146 | # - jdkconf: JDK 8 147 | # jdkver: "8" 148 | # - jdkconf: JDK 11 149 | # jdkver: "11" 150 | # - jdkconf: JDK 17 151 | # jdkver: "17" 152 | # - jdkconf: JDK 21 153 | # jdkver: "21" 154 | # steps: 155 | # - uses: actions/checkout@v3 156 | # - name: Set up JDK 157 | # uses: actions/setup-java@v3 158 | # with: 159 | # distribution: 'temurin' 160 | # java-version: ${{ matrix.jdkver}} 161 | # - uses: msys2/setup-msys2@v2 162 | # with: 163 | # update: true 164 | # install: wget tar make 165 | # - name: Prepare env 166 | # shell: msys2 {0} 167 | # run: PATH="/usr/bin:$PATH" BASH_EXECUTABLE=/usr/bin/bash /usr/bin/bash ./run.sh "${JAVA_HOME}" 168 | # - name: Upload results 169 | # if: ${{ always() }} 170 | # uses: actions/upload-artifact@v3 171 | # with: 172 | # path: "test.*.tar.gz" 173 | 174 | test-linux: 175 | name: "Linux" 176 | runs-on: "ubuntu-latest" 177 | strategy: 178 | fail-fast: false 179 | matrix: 180 | jdkconf: 181 | - JDK 8 182 | - JDK 11 183 | - JDK 17 184 | - JDK 21 185 | include: 186 | - jdkconf: JDK 8 187 | jdkver: "8" 188 | - jdkconf: JDK 11 189 | jdkver: "11" 190 | - jdkconf: JDK 17 191 | jdkver: "17" 192 | - jdkconf: JDK 21 193 | jdkver: "21" 194 | steps: 195 | - uses: actions/checkout@v3 196 | - name: Set up JDK 197 | uses: actions/setup-java@v3 198 | with: 199 | distribution: 'temurin' 200 | java-version: ${{ matrix.jdkver}} 201 | - name: Run 202 | run: make SSLContextInfo SSLSocketInfo ssl-tests 203 | 204 | test-linux-pkcs11-nss-fips: 205 | name: "Linux SunPKCS11-NSS-FIPS" 206 | runs-on: "ubuntu-latest" 207 | strategy: 208 | fail-fast: false 209 | matrix: 210 | jdkconf: 211 | - JDK 8 212 | - JDK 11 213 | - JDK 17 214 | - JDK 21 215 | include: 216 | - jdkconf: JDK 8 217 | jdkver: "8" 218 | - jdkconf: JDK 11 219 | jdkver: "11" 220 | - jdkconf: JDK 17 221 | jdkver: "17" 222 | - jdkconf: JDK 21 223 | jdkver: "21" 224 | steps: 225 | - name: "Install nss" 226 | run: | 227 | sudo apt-get update 228 | sudo apt-get install libnss3 libnss3-tools 229 | - uses: actions/checkout@v3 230 | - name: Set up JDK 231 | uses: actions/setup-java@v3 232 | with: 233 | distribution: 'temurin' 234 | java-version: ${{ matrix.jdkver }} 235 | - name: Run 236 | run: | 237 | make ssl-tests TEST_PKCS11_FIPS=1 238 | 239 | test-linux-openssl-client: 240 | name: "Linux openssl client" 241 | runs-on: "ubuntu-latest" 242 | strategy: 243 | fail-fast: false 244 | matrix: 245 | jdkconf: 246 | - JDK 8 247 | - JDK 11 248 | - JDK 17 249 | - JDK 21 250 | include: 251 | - jdkconf: JDK 8 252 | jdkver: "8" 253 | - jdkconf: JDK 11 254 | jdkver: "11" 255 | - jdkconf: JDK 17 256 | jdkver: "17" 257 | - jdkconf: JDK 21 258 | jdkver: "21" 259 | steps: 260 | - name: "Install openssl" 261 | run: | 262 | sudo apt-get update 263 | sudo apt-get install openssl 264 | - uses: actions/checkout@v3 265 | - name: Set up JDK 266 | uses: actions/setup-java@v3 267 | with: 268 | distribution: 'temurin' 269 | java-version: ${{ matrix.jdkver }} 270 | - name: Run 271 | run: make ssl-tests SSLTESTS_USE_OPENSSL_CLIENT=1 272 | 273 | test-linux-gnutls-client: 274 | name: "Linux gnutls client" 275 | runs-on: "ubuntu-latest" 276 | strategy: 277 | fail-fast: false 278 | matrix: 279 | jdkconf: 280 | - JDK 8 281 | - JDK 11 282 | - JDK 17 283 | - JDK 21 284 | include: 285 | - jdkconf: JDK 8 286 | jdkver: "8" 287 | - jdkconf: JDK 11 288 | jdkver: "11" 289 | - jdkconf: JDK 17 290 | jdkver: "17" 291 | - jdkconf: JDK 21 292 | jdkver: "21" 293 | steps: 294 | - name: "Install gnutls" 295 | run: | 296 | sudo apt-get update 297 | sudo apt-get install gnutls-bin 298 | - uses: actions/checkout@v3 299 | - name: Set up JDK 300 | uses: actions/setup-java@v3 301 | with: 302 | distribution: 'temurin' 303 | java-version: ${{ matrix.jdkver }} 304 | - name: Run 305 | run: make ssl-tests SSLTESTS_USE_GNUTLS_CLIENT=1 306 | 307 | test-linux-nss-client: 308 | name: "Linux nss client" 309 | runs-on: "ubuntu-latest" 310 | strategy: 311 | fail-fast: false 312 | matrix: 313 | jdkconf: 314 | - JDK 8 315 | - JDK 11 316 | - JDK 17 317 | - JDK 21 318 | include: 319 | - jdkconf: JDK 8 320 | jdkver: "8" 321 | - jdkconf: JDK 11 322 | jdkver: "11" 323 | - jdkconf: JDK 17 324 | jdkver: "17" 325 | - jdkconf: JDK 21 326 | jdkver: "21" 327 | steps: 328 | - name: "Install nss" 329 | run: | 330 | sudo apt-get update 331 | sudo apt-get install libnss3-tools libnss3-dev gcc pkg-config 332 | if ! type listsuites ; then 333 | curl -L -f -o listsuites.c https://raw.githubusercontent.com/servo/nss/949eb9848f4fa5f83756f3ab7fdf9b0d3f20d37f/cmd/listsuites/listsuites.c 334 | gcc $( pkg-config --cflags nss ) -o listsuites listsuites.c $( pkg-config --libs nss ) 335 | sudo cp -a listsuites /usr/bin/ 336 | rm -f listsuites listsuites.c 337 | fi 338 | - uses: actions/checkout@v3 339 | - name: Set up JDK 340 | uses: actions/setup-java@v3 341 | with: 342 | distribution: 'temurin' 343 | java-version: ${{ matrix.jdkver }} 344 | - name: Run 345 | run: make ssl-tests SSLTESTS_USE_NSS_CLIENT=1 346 | 347 | test-linux-bcjsse: 348 | name: "Linux BCJSSE" 349 | runs-on: "ubuntu-latest" 350 | strategy: 351 | fail-fast: false 352 | matrix: 353 | jdkconf: 354 | - JDK 8 355 | - JDK 11 356 | - JDK 17 357 | - JDK 21 358 | include: 359 | - jdkconf: JDK 8 360 | jdkver: "8" 361 | - jdkconf: JDK 11 362 | jdkver: "11" 363 | - jdkconf: JDK 17 364 | jdkver: "17" 365 | - jdkconf: JDK 21 366 | jdkver: "21" 367 | steps: 368 | - uses: actions/checkout@v3 369 | - name: Set up JDK 370 | uses: actions/setup-java@v3 371 | with: 372 | distribution: 'temurin' 373 | java-version: ${{ matrix.jdkver }} 374 | - name: Run 375 | run: make ssl-tests TEST_BCJSSE=1 376 | 377 | test-linux-bcfips: 378 | name: "Linux BCFIPS" 379 | runs-on: "ubuntu-latest" 380 | strategy: 381 | fail-fast: false 382 | matrix: 383 | jdkconf: 384 | - JDK 8 385 | - JDK 11 386 | - JDK 17 387 | - JDK 21 388 | include: 389 | - jdkconf: JDK 8 390 | jdkver: "8" 391 | - jdkconf: JDK 11 392 | jdkver: "11" 393 | - jdkconf: JDK 17 394 | jdkver: "17" 395 | - jdkconf: JDK 21 396 | jdkver: "21" 397 | steps: 398 | - uses: actions/checkout@v3 399 | - name: Set up JDK 400 | uses: actions/setup-java@v3 401 | with: 402 | distribution: 'temurin' 403 | java-version: ${{ matrix.jdkver }} 404 | - name: Run 405 | run: make ssl-tests TEST_BCFIPS=1 406 | 407 | test-linux-bc-2nd: 408 | name: "Linux BC 2ND" 409 | runs-on: "ubuntu-latest" 410 | strategy: 411 | fail-fast: false 412 | matrix: 413 | jdkconf: 414 | - JDK 8 415 | - JDK 11 416 | - JDK 17 417 | - JDK 21 418 | include: 419 | - jdkconf: JDK 8 420 | jdkver: "8" 421 | - jdkconf: JDK 11 422 | jdkver: "11" 423 | - jdkconf: JDK 17 424 | jdkver: "17" 425 | - jdkconf: JDK 21 426 | jdkver: "21" 427 | steps: 428 | - uses: actions/checkout@v3 429 | - name: Set up JDK 430 | uses: actions/setup-java@v3 431 | with: 432 | distribution: 'temurin' 433 | java-version: ${{ matrix.jdkver }} 434 | - name: Run 435 | # Legacy algorithms used for keystore as workaround to BC issue: 436 | # https://github.com/bcgit/bc-java/issues/958 437 | run: make ssl-tests TEST_BC_2ND=1 KEYSTORE_PKCS12_LEGACY=1 438 | 439 | test-windows: 440 | name: "Windows" 441 | runs-on: "windows-latest" 442 | strategy: 443 | fail-fast: false 444 | matrix: 445 | jdkconf: 446 | - JDK 8 447 | - JDK 11 448 | - JDK 17 449 | - JDK 21 450 | include: 451 | - jdkconf: JDK 8 452 | jdkver: "8" 453 | - jdkconf: JDK 11 454 | jdkver: "11" 455 | - jdkconf: JDK 17 456 | jdkver: "17" 457 | - jdkconf: JDK 21 458 | jdkver: "21" 459 | steps: 460 | - uses: actions/checkout@v3 461 | - name: Set up JDK 462 | uses: actions/setup-java@v3 463 | with: 464 | distribution: 'temurin' 465 | java-version: ${{ matrix.jdkver }} 466 | - uses: msys2/setup-msys2@v2 467 | with: 468 | update: true 469 | install: make 470 | - name: Run 471 | run: make SSLContextInfo SSLSocketInfo ssl-tests 472 | 473 | test-macos: 474 | name: "MacOS" 475 | runs-on: "macos-latest" 476 | strategy: 477 | fail-fast: false 478 | matrix: 479 | jdkconf: 480 | - JDK 11 481 | - JDK 17 482 | - JDK 21 483 | include: 484 | - jdkconf: JDK 11 485 | jdkver: "11" 486 | - jdkconf: JDK 17 487 | jdkver: "17" 488 | - jdkconf: JDK 21 489 | jdkver: "21" 490 | steps: 491 | - uses: actions/checkout@v3 492 | - name: Set up JDK 493 | uses: actions/setup-java@v3 494 | with: 495 | distribution: 'temurin' 496 | java-version: ${{ matrix.jdkver}} 497 | - name: Run 498 | run: make SSLContextInfo SSLSocketInfo ssl-tests 499 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | JAVA ?= $(shell if [ -n "$(JAVA_HOME)" ] ; then printf '%s/bin/java' "$(JAVA_HOME)" | tr '\\' '/' ; else printf 'java' ; fi ) 2 | JAVAC ?= $(shell if [ -n "$(JAVA_HOME)" ] ; then printf '%s/bin/javac' "$(JAVA_HOME)" | tr '\\' '/' ; else printf 'javac' ; fi ) 3 | KEYTOOL ?= $(shell if [ -n "$(JAVA_HOME)" ] ; then printf '%s/bin/keytool' "$(JAVA_HOME)" | tr '\\' '/' ; else printf 'keytool' ; fi ) 4 | OPENSSL = openssl 5 | 6 | JAVA_VERSION_MAJOR := $(shell $(JAVA) -version 2>&1 | grep version | head -n 1 | sed -E 's/^.*"(1[.])?([0-9]+).*$$/\2/g' ) 7 | JAVA_HOME_DIR := $(shell if [ -n "$(JAVA_HOME)" ] ; then printf '%s' "$(JAVA_HOME)" ; else readlink -f $$( which $(JAVA) 2>/dev/null || type $(JAVA) | sed 's;.* ;;g' ) | sed 's;/bin/java$$;;g' | sed 's;/jre$$;;g' ; fi ) 8 | JAVA_CONF_DIR := $(shell if [ 8 -ge $(JAVA_VERSION_MAJOR) ] ; then printf '%s' "$(JAVA_HOME_DIR)/jre/lib" ; else printf '%s' "$(JAVA_HOME_DIR)/conf" ; fi ) 9 | JAVA_CONF_FIPS = $(shell if cat "$(JAVA_CONF_DIR)/security/java.security" 2>&1 | grep -q '^fips.provider' ; then echo 1 ; else echo 0 ; fi ) 10 | 11 | FIPS_MODE_ENABLED := $(shell if [ -e "/proc/sys/crypto/fips_enabled" ] && [ 1 = $$(cat /proc/sys/crypto/fips_enabled) ] ; then echo 1 ; else echo 0 ; fi ) 12 | TEST_PKCS11_FIPS ?= $(shell if [ 1 = $(FIPS_MODE_ENABLED) ] && [ 1 = $(JAVA_CONF_FIPS) ] ; then echo 1; else echo 0 ; fi ) 13 | NSSDB_FIPS := $(shell if [ 0 = $(FIPS_MODE_ENABLED) ] && [ 1 = $(TEST_PKCS11_FIPS) ] ; then echo 1 ; else echo 0 ; fi ) 14 | NSS_LIBDIR = $(shell \ 15 | if [ -e '/usr/lib64' ] ; then \ 16 | if [ -e /usr/lib64/libnss3.so ] ; then \ 17 | printf '%s' "/usr/lib64" ; \ 18 | else \ 19 | dirname /usr/lib/*linux*/libnss3.so | head -n 1 ; \ 20 | fi \ 21 | else \ 22 | if [ -e /usr/lib/libnss3.so ] ; then \ 23 | printf '%s' "/usr/lib" ; \ 24 | else \ 25 | dirname /usr/lib/*linux*/libnss3.so | head -n 1 ; \ 26 | fi \ 27 | fi \ 28 | ) 29 | KEYTOOL_PARAMS := $(shell printf '%s ' '-J-Dcom.redhat.fips=false' ; if [ 1 = "$(KEYSTORE_PKCS12_LEGACY)" ] ; then printf '%s ' '-J-Dkeystore.pkcs12.legacy' ; fi ) 30 | 31 | TOP_DIR = . 32 | BUILD_DIR = build 33 | 34 | JAVA_PKCS11_FIPS_CONF_DIR = $(BUILD_DIR)/java-pkcs11-conf 35 | JAVA_PKCS11_FIPS_NSS_CFG = $(JAVA_PKCS11_FIPS_CONF_DIR)/nss.fips.cfg 36 | JAVA_PKCS11_FIPS_SECURITY_CFG = $(JAVA_PKCS11_FIPS_CONF_DIR)/java.security 37 | 38 | BC_JARS_DIRS = $(BUILD_DIR)/bc-jars 39 | BC_VERSION = 1.70 40 | BC_VARIANT = jdk15on 41 | BC_BCPROV_VERSION = $(BC_VERSION) 42 | BC_BCTLS_VERSION = $(BC_VERSION) 43 | BC_BCPKIX_VERSION = $(BC_VERSION) 44 | BC_BCUTIL_VERSION = $(BC_VERSION) 45 | BC_BCPROV_JAR = $(BC_JARS_DIRS)/bcprov-$(BC_VARIANT)-$(BC_BCPROV_VERSION).jar 46 | BC_BCTLS_JAR = $(BC_JARS_DIRS)/bctls-$(BC_VARIANT)-$(BC_BCTLS_VERSION).jar 47 | BC_BCPKIX_JAR = $(BC_JARS_DIRS)/bcpkix-$(BC_VARIANT)-$(BC_BCPKIX_VERSION).jar 48 | BC_BCUTIL_JAR = $(BC_JARS_DIRS)/bcutil-$(BC_VARIANT)-$(BC_BCUTIL_VERSION).jar 49 | 50 | BC_BCFIPS_VERSION = 1.0.2.3 51 | BC_BCFIPS_JAR = $(BC_JARS_DIRS)/bc-fips-$(BC_BCFIPS_VERSION).jar 52 | 53 | JAVA_BCFIPS_CONF_DIR = $(BUILD_DIR)/java-bcfips-conf 54 | JAVA_BCFIPS_SECURITY_CFG = $(JAVA_BCFIPS_CONF_DIR)/java.security 55 | 56 | JAVA_BCJSSE_CONF_DIR = $(BUILD_DIR)/java-bcjsse-conf 57 | JAVA_BCJSSE_SECURITY_CFG = $(JAVA_BCJSSE_CONF_DIR)/java.security 58 | 59 | JAVA_BC_2ND_CONF_DIR = $(BUILD_DIR)/java-bc-2nd-conf 60 | JAVA_BC_2ND_SECURITY_CFG = $(JAVA_BC_2ND_CONF_DIR)/java.security 61 | 62 | all: ssl-tests 63 | 64 | CERTGEN_DIR = $(TOP_DIR)/certgen 65 | CERTGEN_BUILD_DIR = $(BUILD_DIR)/certgen 66 | include $(CERTGEN_DIR)/certgen.mk 67 | 68 | # BCFIPS needs workaround for jdk>=13: 69 | # https://github.com/bcgit/bc-java/issues/589#issuecomment-530780788 70 | JAVA_SECURITY_PARAMS := $(shell \ 71 | if [ 1 = "$(TEST_BCFIPS)" ] ; then \ 72 | printf '%s ' -Djava.security.properties==$(JAVA_BCFIPS_SECURITY_CFG) ; \ 73 | printf '%s ' -Djavax.net.ssl.keyStore=$(KEYSTORE_P12) ; \ 74 | printf '%s ' -Djavax.net.ssl.keyStorePassword=$(KEYSTORE_PASSWORD) ; \ 75 | printf '%s ' -Djavax.net.ssl.trustStore=$(TRUSTSTORE_P12) ; \ 76 | printf '%s ' -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) ; \ 77 | printf '%s ' -Dorg.bouncycastle.rsa.allow_multi_use=true ; \ 78 | if [ 13 -le $(JAVA_VERSION_MAJOR) ] ; then \ 79 | printf '%s ' '-Djdk.tls.namedGroups="secp256r1, secp384r1, ffdhe2048, ffdhe3072"' ; \ 80 | fi ; \ 81 | if [ 1 = "$(JAVA_CONF_FIPS)" ] && [ 1 = "$(FIPS_MODE_ENABLED)" ] ; then \ 82 | printf '%s ' '-Dcom.redhat.fips=0' ; \ 83 | fi ; \ 84 | elif [ 1 = "$(TEST_BCJSSE)" ] ; then \ 85 | printf '%s ' -Djava.security.properties==$(JAVA_BCJSSE_SECURITY_CFG) ; \ 86 | printf '%s ' -Djavax.net.ssl.keyStore=$(KEYSTORE_P12) ; \ 87 | printf '%s ' -Djavax.net.ssl.keyStorePassword=$(KEYSTORE_PASSWORD) ; \ 88 | printf '%s ' -Djavax.net.ssl.trustStore=$(TRUSTSTORE_P12) ; \ 89 | printf '%s ' -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) ; \ 90 | if [ 1 = "$(JAVA_CONF_FIPS)" ] && [ 1 = "$(FIPS_MODE_ENABLED)" ] ; then \ 91 | printf '%s ' '-Dcom.redhat.fips=0' ; \ 92 | fi ; \ 93 | elif [ 1 = "$(TEST_BC_2ND)" ] ; then \ 94 | printf '%s ' -Djava.security.properties==$(JAVA_BC_2ND_SECURITY_CFG) ; \ 95 | printf '%s ' -Djavax.net.ssl.keyStore=$(KEYSTORE_P12) ; \ 96 | printf '%s ' -Djavax.net.ssl.keyStorePassword=$(KEYSTORE_PASSWORD) ; \ 97 | printf '%s ' -Djavax.net.ssl.trustStore=$(TRUSTSTORE_P12) ; \ 98 | printf '%s ' -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) ; \ 99 | if [ 1 = "$(JAVA_CONF_FIPS)" ] && [ 1 = "$(FIPS_MODE_ENABLED)" ] ; then \ 100 | printf '%s ' '-Dcom.redhat.fips=0' ; \ 101 | fi ; \ 102 | elif [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then \ 103 | printf '%s ' -Djava.security.properties==$(JAVA_PKCS11_FIPS_SECURITY_CFG) ; \ 104 | if ! [ 1 = "$(JAVA_CONF_FIPS)" ] || ! [ 1 = "$(FIPS_MODE_ENABLED)" ] ; then \ 105 | printf '%s ' '-Djavax.net.ssl.keyStore=NONE' ; \ 106 | else \ 107 | printf '%s ' '-Dcom.redhat.fips=true' ; \ 108 | fi ; \ 109 | if cat "$(JAVA_CONF_DIR)/security/java.security" 2>&1 | grep -q '^fips.keystore.type=pkcs12' ; then \ 110 | printf '%s ' -Djavax.net.ssl.keyStore=$(KEYSTORE_P12) ; \ 111 | printf '%s ' -Djavax.net.ssl.keyStorePassword=$(KEYSTORE_PASSWORD) ; \ 112 | printf '%s ' -Djavax.net.ssl.trustStore=$(TRUSTSTORE_P12) ; \ 113 | printf '%s ' -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) ; \ 114 | fi ; \ 115 | else \ 116 | printf '%s ' -Djavax.net.ssl.keyStore=$(KEYSTORE_P12) ; \ 117 | printf '%s ' -Djavax.net.ssl.keyStorePassword=$(KEYSTORE_PASSWORD) ; \ 118 | printf '%s ' -Djavax.net.ssl.trustStore=$(TRUSTSTORE_P12) ; \ 119 | printf '%s ' -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) ; \ 120 | fi ; \ 121 | if [ 1 = "$(TEST_PKCS11_FIPS)" ] || [ 1 = "$(SSLTESTS_USE_OPENSSL_CLIENT)" ] ; then \ 122 | printf '%s ' -Djdk.tls.ephemeralDHKeySize=2048 ; \ 123 | fi ; \ 124 | if [ 1 = "$(USE_URANDOM)" ] ; then \ 125 | printf '%s ' -Djava.security.egd=file:/dev/./urandom ; \ 126 | fi ; \ 127 | ) 128 | JAVA_SECURITY_DEPS := $(shell \ 129 | if [ 1 = "$(TEST_BCFIPS)" ] ; then \ 130 | printf '%s %s %s %s ' $(JAVA_BCFIPS_SECURITY_CFG) $(BC_BCFIPS_JAR) $(KEYSTORE_P12) $(TRUSTSTORE_P12) ; \ 131 | elif [ 1 = "$(TEST_BCJSSE)" ] ; then \ 132 | printf '%s %s %s %s %s %s %s ' $(JAVA_BCJSSE_SECURITY_CFG) $(BC_BCPROV_JAR) $(BC_BCTLS_JAR) $(BC_BCPKIX_JAR) $(BC_BCUTIL_JAR) $(KEYSTORE_P12) $(TRUSTSTORE_P12) ; \ 133 | elif [ 1 = "$(TEST_BC_2ND)" ] ; then \ 134 | printf '%s %s %s %s %s %s %s ' $(JAVA_BC_2ND_SECURITY_CFG) $(BC_BCPROV_JAR) $(BC_BCTLS_JAR) $(BC_BCPKIX_JAR) $(BC_BCUTIL_JAR) $(KEYSTORE_P12) $(TRUSTSTORE_P12) ; \ 135 | elif [ 1 = "$(TEST_PKCS11_FIPS)" ] ; then \ 136 | printf '%s ' $(JAVA_PKCS11_FIPS_SECURITY_CFG) ; \ 137 | if cat "$(JAVA_CONF_DIR)/security/java.security" 2>&1 | grep -q '^fips.keystore.type=pkcs12' ; then \ 138 | printf '%s %s ' $(KEYSTORE_P12) $(TRUSTSTORE_P12) ; \ 139 | fi ; \ 140 | else \ 141 | printf '%s %s ' $(KEYSTORE_P12) $(TRUSTSTORE_P12) ; \ 142 | fi ; \ 143 | ) 144 | SEP := $(shell if uname -s | grep -qi cygwin ; then printf ';' ; else printf ':' ; fi ) 145 | JAVA_CP_APPEND := $(shell \ 146 | if [ 1 = "$(TEST_BCFIPS)" ] ; then \ 147 | printf "$(SEP)%s" $(BC_BCFIPS_JAR) ; \ 148 | elif [ 1 = "$(TEST_BCJSSE)" ] ; then \ 149 | printf "$(SEP)%s$(SEP)%s$(SEP)%s$(SEP)%s" $(BC_BCPROV_JAR) $(BC_BCTLS_JAR) $(BC_BCPKIX_JAR) $(BC_BCUTIL_JAR) ; \ 150 | elif [ 1 = "$(TEST_BC_2ND)" ] ; then \ 151 | printf "$(SEP)%s$(SEP)%s$(SEP)%s$(SEP)%s" $(BC_BCPROV_JAR) $(BC_BCTLS_JAR) $(BC_BCPKIX_JAR) $(BC_BCUTIL_JAR) ; \ 152 | fi ; \ 153 | ) 154 | 155 | SSLCONTEXTINFO_DIR = $(TOP_DIR)/SSLContextInfo 156 | SSLCONTEXTINFO_CLASSES_DIR = $(BUILD_DIR)/SSLContextInfo 157 | include $(SSLCONTEXTINFO_DIR)/SSLContextInfo.mk 158 | 159 | SSLSOCKETINFO_DIR = $(TOP_DIR)/SSLSocketInfo 160 | SSLSOCKETINFO_CLASSES_DIR = $(BUILD_DIR)/SSLSocketInfo 161 | include $(SSLSOCKETINFO_DIR)/SSLSocketInfo.mk 162 | 163 | SSLTESTS_DIR = $(TOP_DIR)/ssl-tests 164 | SSLTESTS_CLASSES_DIR = $(BUILD_DIR)/ssl-tests 165 | include $(SSLTESTS_DIR)/ssl-tests.mk 166 | 167 | clean: 168 | rm -rf $(BUILD_DIR) 169 | 170 | $(JAVA_PKCS11_FIPS_CONF_DIR): 171 | mkdir $@ 172 | 173 | $(JAVA_BCFIPS_CONF_DIR): 174 | mkdir $@ 175 | 176 | $(JAVA_BCJSSE_CONF_DIR): 177 | mkdir $@ 178 | 179 | $(JAVA_BC_2ND_CONF_DIR): 180 | mkdir $@ 181 | 182 | $(BC_JARS_DIRS): 183 | mkdir $@ 184 | 185 | $(JAVA_PKCS11_FIPS_NSS_CFG): | $(JAVA_PKCS11_FIPS_CONF_DIR) 186 | if [ -e $(JAVA_CONF_DIR)/security/nss.fips.cfg ] ; then \ 187 | cp $(JAVA_CONF_DIR)/security/nss.fips.cfg $@ ; \ 188 | sed -i -e 's;^nssSecmodDirectory[[:space:]]*=.*$$;nssSecmodDirectory = $(NSSDB_DIR);g' $@ ; \ 189 | else \ 190 | printf '%s\n%s\n%s\n%s\n%s\n%s\n' \ 191 | "name = NSS-FIPS" \ 192 | "nssLibraryDirectory = $(NSS_LIBDIR)" \ 193 | "nssSecmodDirectory = $(NSSDB_DIR)" \ 194 | "nssDbMode = readOnly" \ 195 | "nssModule = fips" \ 196 | "attributes(*,CKO_SECRET_KEY,CKK_GENERIC_SECRET)={ CKA_SIGN=true }" \ 197 | >> $@ ; \ 198 | fi 199 | 200 | $(JAVA_PKCS11_FIPS_SECURITY_CFG): $(JAVA_PKCS11_FIPS_NSS_CFG) | $(JAVA_PKCS11_FIPS_CONF_DIR) $(NSSDB_DIR) 201 | cp $(JAVA_CONF_DIR)/security/java.security $@ 202 | printf '\n' >> $@ ; 203 | if cat $@ | grep -q '^fips.provider' && [ 1 = $(FIPS_MODE_ENABLED) ] ; then \ 204 | if [ 8 -ge $(JAVA_VERSION_MAJOR) ] ; then \ 205 | sed -i -e 's;^fips.provider.1=sun.security.pkcs11.SunPKCS11.*$$;fips.provider.1=sun.security.pkcs11.SunPKCS11 $(JAVA_PKCS11_FIPS_NSS_CFG);g' $@ ; \ 206 | else \ 207 | sed -i -e 's;^fips.provider.1=SunPKCS11.*$$;fips.provider.1=SunPKCS11 $(JAVA_PKCS11_FIPS_NSS_CFG);g' $@ ; \ 208 | fi ; \ 209 | if ! [ 0 = "$(SET_RPMS_KEYSTORE_TYPE)" ] \ 210 | && cat $@ 2>&1 | grep -q '^fips.keystore.type=PKCS11' ; then \ 211 | sed -i -e "s;^keystore.type=.*$$;keystore.type=PKCS11;g" $@ ; \ 212 | fi \ 213 | else \ 214 | sed -i -e "s;^security\.provider\.;#security.provider;g" $@ ; \ 215 | sed -i -e 's;^keystore.type=.*$$;keystore.type=PKCS11;g' $@ ; \ 216 | if [ 8 -ge $(JAVA_VERSION_MAJOR) ] ; then \ 217 | printf '%s\n%s\n%s\n%s\n' \ 218 | "security.provider.1=sun.security.pkcs11.SunPKCS11 $(JAVA_PKCS11_FIPS_NSS_CFG)" \ 219 | "security.provider.2=sun.security.provider.Sun" \ 220 | "security.provider.3=sun.security.ec.SunEC" \ 221 | "security.provider.4=com.sun.net.ssl.internal.ssl.Provider SunPKCS11-NSS-FIPS" \ 222 | >> $@ ; \ 223 | else \ 224 | printf '%s\n%s\n%s\n%s\n' \ 225 | "security.provider.1=SunPKCS11 $(JAVA_PKCS11_FIPS_NSS_CFG)" \ 226 | "security.provider.2=SUN" \ 227 | "security.provider.3=SunEC" \ 228 | "security.provider.4=SunJSSE SunPKCS11-NSS-FIPS" \ 229 | >> $@ ; \ 230 | fi ; \ 231 | fi 232 | 233 | 234 | $(BC_BCPROV_JAR): | $(BC_JARS_DIRS) 235 | curl -L -f -o $(BC_BCPROV_JAR) "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-$(BC_VARIANT)/$(BC_BCPROV_VERSION)/bcprov-$(BC_VARIANT)-$(BC_BCPROV_VERSION).jar" 236 | 237 | $(BC_BCTLS_JAR): | $(BC_JARS_DIRS) 238 | curl -L -f -o $(BC_BCTLS_JAR) "https://repo1.maven.org/maven2/org/bouncycastle/bctls-$(BC_VARIANT)/$(BC_BCTLS_VERSION)/bctls-$(BC_VARIANT)-$(BC_BCTLS_VERSION).jar" 239 | 240 | $(BC_BCPKIX_JAR): | $(BC_JARS_DIRS) 241 | curl -L -f -o $(BC_BCPKIX_JAR) "https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-$(BC_VARIANT)/$(BC_BCPKIX_VERSION)/bcpkix-$(BC_VARIANT)-$(BC_BCPKIX_VERSION).jar" 242 | 243 | $(BC_BCUTIL_JAR): | $(BC_JARS_DIRS) 244 | curl -L -f -o $(BC_BCUTIL_JAR) "https://repo1.maven.org/maven2/org/bouncycastle/bcutil-$(BC_VARIANT)/$(BC_BCUTIL_VERSION)/bcutil-$(BC_VARIANT)-$(BC_BCUTIL_VERSION).jar" 245 | 246 | $(BC_BCFIPS_JAR): | $(BC_JARS_DIRS) 247 | curl -L -f -o $(BC_BCFIPS_JAR) "https://repo1.maven.org/maven2/org/bouncycastle/bc-fips/$(BC_BCFIPS_VERSION)/bc-fips-$(BC_BCFIPS_VERSION).jar" 248 | 249 | # See: https://downloads.bouncycastle.org/fips-java/BC-FJA-UserGuide-1.0.2.pdf 250 | # this setup requires BCFIPS provider as BC provider does not provide "SunTlsMasterSecret": 251 | # https://github.com/openjdk/jdk/blob/05a764f4ffb8030d6b768f2d362c388e5aabd92d/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java#L105 252 | # this prevents testing anything else than TLSv1.3 253 | # C:HYBRID;ENABLE{All}; should make BC less entropy hungry, see section 2.3 of guide higer 254 | 255 | $(JAVA_BCFIPS_SECURITY_CFG): | $(JAVA_BCFIPS_CONF_DIR) 256 | cp $(JAVA_CONF_DIR)/security/java.security $@ 257 | printf '\n' >> $@ ; 258 | if cat $@ | grep -q '^fips.provider' ; then \ 259 | sed -i -e 's;^fips.provider;#fips.provider;g' $@ ; \ 260 | if [ 8 -ge $(JAVA_VERSION_MAJOR) ] ; then \ 261 | printf '%s\n%s\n%s\n' \ 262 | "fips.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider C:HYBRID;ENABLE{All};" \ 263 | "fips.provider.2=com.sun.net.ssl.internal.ssl.Provider BCFIPS" \ 264 | "fips.provider.3=sun.security.provider.Sun" \ 265 | >> $@ ; \ 266 | else \ 267 | printf '%s\n%s\n%s\n' \ 268 | "fips.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider C:HYBRID;ENABLE{All};" \ 269 | "fips.provider.2=SunJSSE BCFIPS" \ 270 | "fips.provider.3=sun.security.provider.Sun" \ 271 | >> $@ ; \ 272 | fi ; \ 273 | fi 274 | sed -i -e 's;^security.provider;#security.provider;g' $@ 275 | sed -i -e 's;keystore.type=.*;keystore.type=pkcs12;g' $@ 276 | if [ 8 -ge $(JAVA_VERSION_MAJOR) ] ; then \ 277 | printf '%s\n%s\n%s\n%s\n' \ 278 | "security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider C:HYBRID;ENABLE{All};" \ 279 | "security.provider.2=com.sun.net.ssl.internal.ssl.Provider BCFIPS" \ 280 | "security.provider.3=sun.security.provider.Sun" \ 281 | "ssl.KeyManagerFactory.algorithm=PKIX" \ 282 | >> $@ ; \ 283 | else \ 284 | printf '%s\n%s\n%s\n' \ 285 | "security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider C:HYBRID;ENABLE{All};" \ 286 | "security.provider.2=SunJSSE BCFIPS" \ 287 | "security.provider.3=sun.security.provider.Sun" \ 288 | >> $@ ; \ 289 | fi 290 | 291 | # See: https://downloads.bouncycastle.org/fips-java/BC-FJA-(D)TLSUserGuide-1.0.9.pdf 292 | $(JAVA_BCJSSE_SECURITY_CFG): | $(JAVA_BCJSSE_CONF_DIR) 293 | cp $(JAVA_CONF_DIR)/security/java.security $@ 294 | printf '\n' >> $@ ; 295 | if cat $@ | grep -q '^fips.provider' ; then \ 296 | sed -i -e 's;^fips.provider;#fips.provider;g' $@ ; \ 297 | printf '%s\n%s\n%s\n' \ 298 | "fips.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider" \ 299 | "fips.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider BC" \ 300 | "fips.provider.3=sun.security.provider.Sun" \ 301 | >> $@ ; \ 302 | fi 303 | sed -i -e 's;^security.provider;#security.provider;g' $@ 304 | sed -i -e 's;keystore.type=.*;keystore.type=pkcs12;g' $@ 305 | printf '%s\n%s\n%s\n' \ 306 | "security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider" \ 307 | "security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider BC" \ 308 | "security.provider.3=sun.security.provider.Sun" \ 309 | >> $@ ; 310 | # http://bouncy-castle.1462172.n4.nabble.com/BC-FIPS-does-not-reject-JKS-keystores-tp4659800.html 311 | printf '%s\n' \ 312 | "ssl.KeyManagerFactory.algorithm=X509" \ 313 | >> $@ ; 314 | 315 | # BC inserted as second provider, see: 316 | # https://docs.oracle.com/cd/E19830-01/819-4712/ablsc/index.html 317 | # http://tomee.apache.org/bouncy-castle.html 318 | # https://bugs.openjdk.java.net/browse/JDK-8256252 319 | $(JAVA_BC_2ND_SECURITY_CFG): | $(JAVA_BC_2ND_CONF_DIR) 320 | cp $(JAVA_CONF_DIR)/security/java.security $@ 321 | printf '\n' >> $@ ; 322 | i=2 ; \ 323 | while cat $@ | grep -q "^security.provider.$${i}[[:space:]]*=" ; do \ 324 | i=$$(( i + 1 )) ; \ 325 | done ; \ 326 | while [ $${i} -ge 2 ] ; do \ 327 | sed -i -e "s;^security.provider.$${i}[[:space:]]*=;security.provider.$$(( i + 1 ))=;g" $@ ; \ 328 | i=$$(( i - 1 )) ; \ 329 | done 330 | sed -i -e 's;keystore.type=.*;keystore.type=pkcs12;g' $@ 331 | printf '%s\n' \ 332 | "security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider" \ 333 | >> $@ ; 334 | if cat $@ | grep -q '^fips.provider' ; then \ 335 | sed -i -e 's;^fips.provider;#fips.provider;g' $@ ; \ 336 | providers="$$( cat $@ | grep '^security.provider.*$$' )" ; \ 337 | printf '%s\n' "$${providers}" | sed 's;^security.provider;fips.provider;g' \ 338 | >> $@ ; \ 339 | fi 340 | 341 | java-pkcs11-fips-conf: $(JAVA_PKCS11_FIPS_SECURITY_CFG) 342 | -------------------------------------------------------------------------------- /ssl-tests/src/SSLSocketTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2020 Zdeněk Žamberský. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | import java.io.FileInputStream; 26 | import java.io.IOException; 27 | import java.security.KeyStore; 28 | import java.security.NoSuchAlgorithmException; 29 | import java.security.Provider; 30 | import java.security.SecureRandom; 31 | import java.security.Security; 32 | import java.util.Set; 33 | import java.util.HashSet; 34 | import java.util.logging.Level; 35 | import java.util.logging.Logger; 36 | import java.util.regex.Pattern; 37 | import javax.net.ssl.KeyManager; 38 | import javax.net.ssl.KeyManagerFactory; 39 | import javax.net.ssl.SSLContext; 40 | import javax.net.ssl.SSLParameters; 41 | import javax.net.ssl.SSLServerSocketFactory; 42 | import javax.net.ssl.SSLSocketFactory; 43 | import javax.net.ssl.TrustManager; 44 | import javax.net.ssl.TrustManagerFactory; 45 | 46 | public class SSLSocketTester { 47 | 48 | KeyManager[] serverKeyManagers; 49 | TrustManager[] serverTrustManagers; 50 | KeyManager[] clientKeyManagers; 51 | TrustManager[] clientTrustManagers; 52 | 53 | boolean onlySSLDefaults; 54 | String[] sslConfigFilterParts = null; 55 | static boolean ignoreSomeEx = true; 56 | boolean failed; 57 | 58 | Pattern ignoredCiphersPattern = null; 59 | Pattern ignoredProtocolsPattern = null; 60 | boolean useOpensslClient = false; 61 | boolean useGnutlsClient = false; 62 | boolean useNssClient = false; 63 | boolean serverShutdownOutput = false; 64 | 65 | public SSLSocketTester() { 66 | 67 | } 68 | 69 | private static boolean getBooleanProperty(String name, boolean defaultValue) { 70 | String val = System.getProperty(name); 71 | if (val != null) { 72 | String valLow = val.toLowerCase(); 73 | if (valLow.equals("1") || valLow.equals("true")) { 74 | return true; 75 | } else if (valLow.equals("0") || valLow.equals("false")) { 76 | return false; 77 | } 78 | } 79 | return defaultValue; 80 | } 81 | 82 | public void init() throws Exception { 83 | String serverKeystoreFile = System.getProperty("javax.net.ssl.keyStore"); 84 | String serverKeystorePassword = System.getProperty("javax.net.ssl.keyStorePassword"); 85 | String clientTruststoreFile = System.getProperty("javax.net.ssl.trustStore"); 86 | String clientTruststorePassword = System.getProperty("javax.net.ssl.trustStorePassword"); 87 | if (serverKeystoreFile == null || serverKeystoreFile.equals("NONE")) { 88 | // fips mode 89 | serverKeyManagers = getKeyManagers(null, 90 | "nss.SECret.123"); 91 | clientTrustManagers = getTrustManagers(null, 92 | "nss.SECret.123"); 93 | } else { 94 | serverKeyManagers = getKeyManagers(serverKeystoreFile, 95 | serverKeystorePassword); 96 | clientTrustManagers = getTrustManagers(clientTruststoreFile, 97 | clientTruststorePassword); 98 | } 99 | onlySSLDefaults = getBooleanProperty("ssltests.onlyssldefaults", true); 100 | String sslConfigFilter = System.getProperty("ssltests.sslconfigFilter"); 101 | if (sslConfigFilter != null) { 102 | String[] sslConfigFilterParts1 = sslConfigFilter.split(","); 103 | if (sslConfigFilterParts1.length == 4) { 104 | sslConfigFilterParts = sslConfigFilterParts1; 105 | } 106 | } 107 | String ignoredCiphersPatternString = System.getProperty("ssltests.ignoredCiphersPattern"); 108 | if (ignoredCiphersPatternString != null) { 109 | ignoredCiphersPattern = Pattern.compile(ignoredCiphersPatternString); 110 | } 111 | String ignoredProtocolsPatternString = System.getProperty("ssltests.ignoredProtocolsPattern"); 112 | if (ignoredProtocolsPatternString != null) { 113 | ignoredProtocolsPattern = Pattern.compile(ignoredProtocolsPatternString); 114 | } 115 | 116 | useOpensslClient = getBooleanProperty("ssltests.useOpensslClient", false); 117 | useGnutlsClient = getBooleanProperty("ssltests.useGnutlsClient", false); 118 | useNssClient = getBooleanProperty("ssltests.useNssClient", false); 119 | serverShutdownOutput = SSLSocketTester.getBooleanProperty("ssltests.serverShutdownOutput", false); 120 | } 121 | 122 | KeyManager[] getKeyManagers(String file, String password) throws Exception { 123 | KeyStore keyStore = loadKeystore(file, password); 124 | String keyManagerDefaultAlg = KeyManagerFactory.getDefaultAlgorithm(); 125 | KeyManagerFactory keyManagerFactory 126 | = KeyManagerFactory.getInstance(keyManagerDefaultAlg); 127 | keyManagerFactory.init(keyStore, password.toCharArray()); 128 | return keyManagerFactory.getKeyManagers(); 129 | } 130 | 131 | TrustManager[] getTrustManagers( 132 | String file, 133 | String password) throws Exception { 134 | KeyStore keyStore = loadKeystore(file, password); 135 | String trustManagerDefAlg = TrustManagerFactory.getDefaultAlgorithm(); 136 | TrustManagerFactory trustManagerFactory 137 | = TrustManagerFactory.getInstance(trustManagerDefAlg); 138 | trustManagerFactory.init(keyStore); 139 | return trustManagerFactory.getTrustManagers(); 140 | } 141 | 142 | KeyStore loadKeystore(String file, String password) throws Exception { 143 | String defaultType = KeyStore.getDefaultType(); 144 | KeyStore keystore = KeyStore.getInstance(defaultType); 145 | char[] passwordArray = password == null ? null : password.toCharArray(); 146 | if (file != null) { 147 | try (FileInputStream fis = new FileInputStream(file)) { 148 | keystore.load(fis, passwordArray); 149 | } 150 | } else { 151 | keystore.load(null, passwordArray); 152 | } 153 | return keystore; 154 | } 155 | 156 | public void testSingle( 157 | String providerName, 158 | String alghoritm, 159 | String protocol, 160 | String cipher) throws Exception { 161 | Provider provider = Security.getProvider(providerName); 162 | SSLContext serverContext 163 | = SSLContext.getInstance(alghoritm, provider); 164 | SSLContext clientContext 165 | = SSLContext.getInstance(alghoritm, provider); 166 | serverContext.init(serverKeyManagers, 167 | serverTrustManagers, 168 | new SecureRandom()); 169 | clientContext.init(clientKeyManagers, 170 | clientTrustManagers, 171 | new SecureRandom()); 172 | testConfiguration( 173 | serverContext, 174 | clientContext, 175 | protocol, 176 | cipher, 177 | false); 178 | } 179 | 180 | public void testProviders() throws Exception { 181 | Provider[] providers = Security.getProviders(); 182 | for (Provider provider : providers) { 183 | if (providesSSLContext(provider)) { 184 | if (sslConfigFilterParts != null 185 | && !sslConfigFilterParts[0].equals(provider.getName())) { 186 | continue; 187 | } 188 | 189 | // System.out.println("Provider: " + provider.getName()); 190 | testProvider(provider); 191 | } 192 | } 193 | } 194 | 195 | public boolean isSSLContext(Provider.Service service) { 196 | return service.getType().equals("SSLContext"); 197 | } 198 | 199 | public boolean providesSSLContext(Provider provider) { 200 | Set services = provider.getServices(); 201 | for (Provider.Service service : services) { 202 | if (isSSLContext(service)) { 203 | return true; 204 | } 205 | } 206 | return false; 207 | } 208 | 209 | public void testProvider(Provider provider) throws Exception { 210 | Set services = provider.getServices(); 211 | for (Provider.Service service : services) { 212 | if (isSSLContext(service)) { 213 | String alghorithm = service.getAlgorithm(); 214 | if (sslConfigFilterParts != null 215 | && !sslConfigFilterParts[1].equals(alghorithm)) { 216 | continue; 217 | } 218 | 219 | SSLContext serverContext 220 | = SSLContext.getInstance(alghorithm, provider); 221 | SSLContext clientContext 222 | = SSLContext.getInstance(alghorithm, provider); 223 | /* Default contexts are auto initialized */ 224 | if (!serverContext.getProtocol().toUpperCase().equals("DEFAULT")) { 225 | serverContext.init(serverKeyManagers, 226 | serverTrustManagers, 227 | new SecureRandom()); 228 | } 229 | if (!clientContext.getProtocol().toUpperCase().equals("DEFAULT")) { 230 | clientContext.init(clientKeyManagers, 231 | clientTrustManagers, 232 | new SecureRandom()); 233 | } 234 | testConfigurations(serverContext, clientContext); 235 | } 236 | } 237 | } 238 | 239 | public void testConfigurations( 240 | SSLContext sslServerContext, 241 | SSLContext sslClientContext) { 242 | SSLParameters sslParameters 243 | = onlySSLDefaults ? sslServerContext.getDefaultSSLParameters() 244 | : sslServerContext.getSupportedSSLParameters(); 245 | boolean isBC = sslClientContext.getProvider().getName().equals("BCJSSE"); 246 | for (String protocol 247 | : sslParameters.getProtocols()) { 248 | boolean skippedProtocol = false; 249 | if (protocol.equals("SSLv2Hello")) { 250 | skippedProtocol = true; 251 | } 252 | /* 253 | DTLS is not supported yet by this test 254 | */ 255 | if (protocol.startsWith("DTLS")) { 256 | skippedProtocol = true; 257 | } 258 | if (ignoredProtocolsPattern != null 259 | && ignoredProtocolsPattern.matcher(protocol).matches()) { 260 | skippedProtocol = true; 261 | } 262 | Set validCiphers = null; 263 | if (!skippedProtocol) { 264 | try { 265 | if (useOpensslClient) { 266 | validCiphers = OpensslClient.getSupportedCiphers(protocol); 267 | } else if (useGnutlsClient) { 268 | validCiphers = GnutlsClient.getSupportedCiphers(protocol); 269 | } else if (useNssClient) { 270 | validCiphers = NssClient.getSupportedCiphers(protocol); 271 | } else if (isBC) { 272 | SSLParameters sslparams = onlySSLDefaults ? 273 | sslClientContext.getDefaultSSLParameters() : 274 | sslClientContext.getSupportedSSLParameters(); 275 | validCiphers = new HashSet(); 276 | for (String cipher : sslparams.getCipherSuites()) { 277 | if (ExternalClient.testCompatible(protocol, cipher, null)) { 278 | validCiphers.add(cipher); 279 | } 280 | } 281 | } 282 | } catch (Exception ex) { 283 | throw new RuntimeException(ex); 284 | } 285 | } 286 | if (sslConfigFilterParts != null 287 | && !sslConfigFilterParts[2].equals(protocol)) { 288 | continue; 289 | } 290 | for (String cipher : sslParameters.getCipherSuites()) { 291 | if (sslConfigFilterParts != null 292 | && !sslConfigFilterParts[3].equals(cipher)) { 293 | continue; 294 | } 295 | boolean skipTesting = skippedProtocol; 296 | /* 297 | TLS_EMPTY_RENEGOTIATION_INFO_SCSV is skipped 298 | as it is not really a cipher, see: 299 | https://tools.ietf.org/html/rfc5746#section-3.3 300 | */ 301 | if (cipher.equals("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { 302 | skipTesting = true; 303 | } 304 | /* 305 | kerberos seems to need more complicated setup, 306 | not yet supported (ignore for now): 307 | https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/d5c320d784e5/test/sun/security/krb5/auto/SSL.java 308 | */ 309 | if (cipher.startsWith("TLS_KRB5")) { 310 | skipTesting = true; 311 | } 312 | if (ignoredCiphersPattern != null 313 | && ignoredCiphersPattern.matcher(cipher).matches()) { 314 | skipTesting = true; 315 | } 316 | 317 | if ((useOpensslClient || useGnutlsClient || useNssClient || isBC) && validCiphers != null) { 318 | if (!validCiphers.contains(cipher)) { 319 | skipTesting = true; 320 | } 321 | } 322 | testConfiguration(sslServerContext, 323 | sslClientContext, 324 | protocol, 325 | cipher, skipTesting); 326 | } 327 | } 328 | } 329 | 330 | public void testConfiguration( 331 | SSLContext sslServerContext, 332 | SSLContext sslClientContext, 333 | String protocol, 334 | String cipher, 335 | boolean skipTesting) { 336 | if (sslServerContext.getProvider() != sslClientContext.getProvider()) { 337 | // should not happen, if not bug in test 338 | throw new RuntimeException( 339 | "Server and Client does not have mathing provider!"); 340 | } 341 | if (!sslServerContext.getProtocol() 342 | .equals(sslClientContext.getProtocol())) { 343 | // should not happen, if not bug in test 344 | throw new RuntimeException( 345 | "Server and Client does not have mathing protocol!"); 346 | } 347 | String providerName = sslServerContext.getProvider().getName(); 348 | String algorithmName = sslServerContext.getProtocol(); 349 | 350 | if (skipTesting) { 351 | printResult(providerName, algorithmName, protocol, cipher, "IGNORED"); 352 | return; 353 | } 354 | 355 | sslServerContext.getProvider().getName(); 356 | sslServerContext.getProtocol(); 357 | 358 | String[] enabledProtocols = new String[]{protocol}; 359 | String[] enabledCiphers = new String[]{cipher}; 360 | 361 | SSLServerSocketFactory sslServerSocketFactory 362 | = sslServerContext.getServerSocketFactory(); 363 | 364 | SSLSocketFactory sslSocketFactory 365 | = sslClientContext.getSocketFactory(); 366 | 367 | SSLSocketServer sslSocketServer 368 | = new SSLSocketServer( 369 | sslServerSocketFactory, 370 | enabledProtocols, 371 | enabledCiphers); 372 | if (serverShutdownOutput) { 373 | sslSocketServer.shutdownOutput = true; 374 | } 375 | 376 | SSLSocketClient sslSocketClient; 377 | if (useOpensslClient) { 378 | sslSocketClient = new OpensslClient(); 379 | } else if (useGnutlsClient) { 380 | sslSocketClient = new GnutlsClient(); 381 | } else if (useNssClient) { 382 | sslSocketClient = new NssClient(); 383 | } else { 384 | sslSocketClient = new SSLSocketClient( 385 | sslSocketFactory, 386 | enabledProtocols, 387 | enabledCiphers); 388 | } 389 | try { 390 | try { 391 | sslSocketServer.start(); 392 | sslSocketClient.test( 393 | sslSocketServer.getHost(), 394 | sslSocketServer.getPort()); 395 | printResult(providerName, algorithmName, protocol, cipher, "PASSED"); 396 | } finally { 397 | sslSocketServer.stop(); 398 | } 399 | } catch (Exception ex) { 400 | String resultStr; 401 | if (isOkException(ex)) { 402 | resultStr = "IGNORED"; 403 | } else { 404 | failed = true; 405 | resultStr = "FAILED"; 406 | Logger.getLogger(SSLSocketTester.class.getName()).log(Level.SEVERE, null, ex); 407 | } 408 | printResult(providerName, algorithmName, protocol, cipher, resultStr); 409 | } 410 | } 411 | 412 | public void printResult( 413 | String providerName, 414 | String agortihm, 415 | String protocol, 416 | String cipher, 417 | String result) { 418 | StringBuilder sb = new StringBuilder(); 419 | sb.append(result); 420 | sb.append(": "); 421 | sb.append(providerName); 422 | sb.append("/"); 423 | sb.append(agortihm); 424 | sb.append(": "); 425 | sb.append(protocol); 426 | sb.append(" + "); 427 | sb.append(cipher); 428 | sb.append("\n"); 429 | System.out.print(sb.toString()); 430 | } 431 | 432 | public static boolean isOkException(Exception ex) { 433 | if (ignoreSomeEx) { 434 | /* 435 | This exception is thrown by handshaker, 436 | when invalid protocol/cipher combination is used, 437 | see: 438 | https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/ce1f37506608/src/share/classes/sun/security/ssl/Handshaker.java#l554 439 | */ 440 | String message = ex.getMessage(); 441 | if (message != null) { 442 | return message.contains("No appropriate protocol (protocol is disabled or cipher suites are inappropriate)"); 443 | } 444 | } 445 | return false; 446 | } 447 | 448 | } 449 | --------------------------------------------------------------------------------