Path: blob/master/test/jdk/sun/security/pkcs11/sslecc/CipherTest.java
41152 views
/*1* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.*;24import java.net.*;25import java.util.*;26import java.util.concurrent.*;2728import java.security.*;29import java.security.cert.*;3031import javax.net.ssl.*;3233/**34* Test that all ciphersuites work in all versions and all client35* authentication types. The way this is setup the server is stateless and36* all checking is done on the client side.37*38* The test is multithreaded to speed it up, especially on multiprocessor39* machines. To simplify debugging, run with -DnumThreads=1.40*41* @author Andreas Sterbenz42*/43public class CipherTest {4445// use any available port for the server socket46static volatile int serverPort = 0;4748static final int THREADS = Integer.getInteger("numThreads", 4);49static final String TEST_SRC = System.getProperty("test.src", ".");5051// assume that if we do not read anything for 20 seconds, something52// has gone wrong53final static int TIMEOUT = 20 * 1000;5455static KeyStore trustStore, keyStore;56static X509ExtendedKeyManager keyManager;57static X509TrustManager trustManager;58static SecureRandom secureRandom;5960private static PeerFactory peerFactory;6162static final CountDownLatch clientCondition = new CountDownLatch(1);6364static abstract class Server implements Runnable {6566final CipherTest cipherTest;6768Server(CipherTest cipherTest) throws Exception {69this.cipherTest = cipherTest;70}7172@Override73public abstract void run();7475void handleRequest(InputStream in, OutputStream out) throws IOException {76boolean newline = false;77StringBuilder sb = new StringBuilder();78while (true) {79int ch = in.read();80if (ch < 0) {81throw new EOFException();82}83sb.append((char)ch);84if (ch == '\r') {85// empty86} else if (ch == '\n') {87if (newline) {88// 2nd newline in a row, end of request89break;90}91newline = true;92} else {93newline = false;94}95}96String request = sb.toString();97if (request.startsWith("GET / HTTP/1.") == false) {98throw new IOException("Invalid request: " + request);99}100out.write("HTTP/1.0 200 OK\r\n\r\n".getBytes());101}102103}104105public static class TestParameters {106107CipherSuite cipherSuite;108Protocol protocol;109String clientAuth;110111TestParameters(CipherSuite cipherSuite, Protocol protocol,112String clientAuth) {113this.cipherSuite = cipherSuite;114this.protocol = protocol;115this.clientAuth = clientAuth;116}117118boolean isEnabled() {119return cipherSuite.supportedByProtocol(protocol);120}121122@Override123public String toString() {124String s = cipherSuite + " in " + protocol + " mode";125if (clientAuth != null) {126s += " with " + clientAuth + " client authentication";127}128return s;129}130}131132private List<TestParameters> tests;133private Iterator<TestParameters> testIterator;134private SSLSocketFactory factory;135private boolean failed;136137private CipherTest(PeerFactory peerFactory) throws IOException {138factory = (SSLSocketFactory)SSLSocketFactory.getDefault();139SSLSocket socket = (SSLSocket)factory.createSocket();140String[] cipherSuites = socket.getSupportedCipherSuites();141String[] protocols = socket.getSupportedProtocols();142String[] clientAuths = {null, "RSA", "DSA", "ECDSA"};143tests = new ArrayList<TestParameters>(144cipherSuites.length * protocols.length * clientAuths.length);145for (int i = 0; i < cipherSuites.length; i++) {146String cipherSuite = cipherSuites[i];147148for (int j = 0; j < protocols.length; j++) {149String protocol = protocols[j];150151if (!peerFactory.isSupported(cipherSuite, protocol)) {152continue;153}154155for (int k = 0; k < clientAuths.length; k++) {156String clientAuth = clientAuths[k];157// no client with anonymous cipher suites.158// TLS_EMPTY_RENEGOTIATION_INFO_SCSV always be skipped.159// TLS 1.3 is skipped due to the signature algorithm,160// exactly MD5withRSA, in the certificates is not allowed.161if ((clientAuth != null && cipherSuite.contains("DH_anon")162|| cipherSuite.equals(163CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV.name())164|| "TLSv1.3".equals(protocol))) {165continue;166}167168tests.add(new TestParameters(169CipherSuite.cipherSuite(cipherSuite),170Protocol.protocol(protocol),171clientAuth));172}173}174}175176testIterator = tests.iterator();177}178179synchronized void setFailed() {180failed = true;181}182183public void run() throws Exception {184Thread[] threads = new Thread[THREADS];185for (int i = 0; i < THREADS; i++) {186try {187threads[i] = new Thread(peerFactory.newClient(this),188"Client " + i);189} catch (Exception e) {190e.printStackTrace();191return;192}193threads[i].start();194}195196// The client threads are ready.197clientCondition.countDown();198199try {200for (int i = 0; i < THREADS; i++) {201threads[i].join();202}203} catch (InterruptedException e) {204setFailed();205e.printStackTrace();206}207if (failed) {208throw new Exception("*** Test '" + peerFactory.getName() +209"' failed ***");210} else {211System.out.println("Test '" + peerFactory.getName() +212"' completed successfully");213}214}215216synchronized TestParameters getTest() {217if (failed) {218return null;219}220if (testIterator.hasNext()) {221return (TestParameters)testIterator.next();222}223return null;224}225226SSLSocketFactory getFactory() {227return factory;228}229230static abstract class Client implements Runnable {231232final CipherTest cipherTest;233234Client(CipherTest cipherTest) throws Exception {235this.cipherTest = cipherTest;236}237238@Override239public final void run() {240while (true) {241TestParameters params = cipherTest.getTest();242if (params == null) {243// no more tests244break;245}246if (params.isEnabled() == false) {247System.out.println("Skipping disabled test " + params);248continue;249}250try {251runTest(params);252System.out.println("Passed " + params);253} catch (SocketTimeoutException ste) {254System.out.println("The client connects to the server timeout, "255+ "so ignore the test.");256break;257} catch (Exception e) {258cipherTest.setFailed();259System.out.println("** Failed " + params + "**");260e.printStackTrace();261}262}263}264265abstract void runTest(TestParameters params) throws Exception;266267void sendRequest(InputStream in, OutputStream out) throws IOException {268out.write("GET / HTTP/1.0\r\n\r\n".getBytes());269out.flush();270StringBuilder sb = new StringBuilder();271while (true) {272int ch = in.read();273if (ch < 0) {274break;275}276sb.append((char)ch);277}278String response = sb.toString();279if (response.startsWith("HTTP/1.0 200 ") == false) {280throw new IOException("Invalid response: " + response);281}282}283284}285286// for some reason, ${test.src} has a different value when the287// test is called from the script and when it is called directly...288static String pathToStores = ".";289static String pathToStoresSH = ".";290static String keyStoreFile = "keystore";291static String trustStoreFile = "truststore";292static char[] passwd = "passphrase".toCharArray();293294static File PATH;295296private static KeyStore readKeyStore(String name) throws Exception {297File file = new File(PATH, name);298KeyStore ks;299try (InputStream in = new FileInputStream(file)) {300ks = KeyStore.getInstance("JKS");301ks.load(in, passwd);302}303return ks;304}305306public static void main(PeerFactory peerFactory, String[] args)307throws Exception {308long time = System.currentTimeMillis();309String relPath;310if ((args != null) && (args.length > 0) && args[0].equals("sh")) {311relPath = pathToStoresSH;312} else {313relPath = pathToStores;314}315PATH = new File(TEST_SRC, relPath);316CipherTest.peerFactory = peerFactory;317System.out.print(318"Initializing test '" + peerFactory.getName() + "'...");319secureRandom = new SecureRandom();320secureRandom.nextInt();321trustStore = readKeyStore(trustStoreFile);322keyStore = readKeyStore(keyStoreFile);323KeyManagerFactory keyFactory =324KeyManagerFactory.getInstance(325KeyManagerFactory.getDefaultAlgorithm());326keyFactory.init(keyStore, passwd);327keyManager = (X509ExtendedKeyManager)keyFactory.getKeyManagers()[0];328trustManager = new AlwaysTrustManager();329330CipherTest cipherTest = new CipherTest(peerFactory);331Thread serverThread = new Thread(peerFactory.newServer(cipherTest),332"Server");333serverThread.setDaemon(true);334serverThread.start();335System.out.println("Done");336cipherTest.run();337time = System.currentTimeMillis() - time;338System.out.println("Done. (" + time + " ms)");339}340341static abstract class PeerFactory {342343abstract String getName();344345abstract Client newClient(CipherTest cipherTest) throws Exception;346347abstract Server newServer(CipherTest cipherTest) throws Exception;348349boolean isSupported(String cipherSuite, String protocol) {350// skip kerberos cipher suites351if (cipherSuite.startsWith("TLS_KRB5")) {352System.out.println("Skipping unsupported test for " +353cipherSuite + " of " + protocol);354return false;355}356357// skip SSLv2Hello protocol358if (protocol.equals("SSLv2Hello")) {359System.out.println("Skipping unsupported test for " +360cipherSuite + " of " + protocol);361return false;362}363364// ignore exportable cipher suite for TLSv1.1365if (protocol.equals("TLSv1.1")) {366if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {367System.out.println("Skipping obsoleted test for " +368cipherSuite + " of " + protocol);369return false;370}371}372373return true;374}375}376377}378379// we currently don't do any chain verification. we assume that works ok380// and we can speed up the test. we could also just add a plain certificate381// chain comparision with our trusted certificates.382class AlwaysTrustManager implements X509TrustManager {383384public AlwaysTrustManager() {385386}387388@Override389public void checkClientTrusted(X509Certificate[] chain, String authType)390throws CertificateException {391// empty392}393394@Override395public void checkServerTrusted(X509Certificate[] chain, String authType)396throws CertificateException {397// empty398}399400@Override401public X509Certificate[] getAcceptedIssuers() {402return new X509Certificate[0];403}404}405406class MyX509KeyManager extends X509ExtendedKeyManager {407408private final X509ExtendedKeyManager keyManager;409private String authType;410411MyX509KeyManager(X509ExtendedKeyManager keyManager) {412this.keyManager = keyManager;413}414415void setAuthType(String authType) {416this.authType = "ECDSA".equals(authType) ? "EC" : authType;417}418419@Override420public String[] getClientAliases(String keyType, Principal[] issuers) {421if (authType == null) {422return null;423}424return keyManager.getClientAliases(authType, issuers);425}426427@Override428public String chooseClientAlias(String[] keyType, Principal[] issuers,429Socket socket) {430if (authType == null) {431return null;432}433return keyManager.chooseClientAlias(new String[] {authType},434issuers, socket);435}436437@Override438public String chooseEngineClientAlias(String[] keyType,439Principal[] issuers, SSLEngine engine) {440if (authType == null) {441return null;442}443return keyManager.chooseEngineClientAlias(new String[] {authType},444issuers, engine);445}446447@Override448public String[] getServerAliases(String keyType, Principal[] issuers) {449throw new UnsupportedOperationException("Servers not supported");450}451452@Override453public String chooseServerAlias(String keyType, Principal[] issuers,454Socket socket) {455throw new UnsupportedOperationException("Servers not supported");456}457458@Override459public String chooseEngineServerAlias(String keyType, Principal[] issuers,460SSLEngine engine) {461throw new UnsupportedOperationException("Servers not supported");462}463464@Override465public X509Certificate[] getCertificateChain(String alias) {466return keyManager.getCertificateChain(alias);467}468469@Override470public PrivateKey getPrivateKey(String alias) {471return keyManager.getPrivateKey(alias);472}473474}475476class DaemonThreadFactory implements ThreadFactory {477478final static ThreadFactory INSTANCE = new DaemonThreadFactory();479480private final static ThreadFactory DEFAULT = Executors.defaultThreadFactory();481482@Override483public Thread newThread(Runnable r) {484Thread t = DEFAULT.newThread(r);485t.setDaemon(true);486return t;487}488489}490491492