87c6761704
Co-authored-by: Adam Petcher <adam.petcher@oracle.com> Co-authored-by: Amanda Jiang <amanda.jiang@oracle.com> Co-authored-by: Anthony Scarpino <anthony.scarpino@oracle.com> Co-authored-by: Bradford Wetmore <bradford.wetmore@oracle.com> Co-authored-by: Jamil Nimeh <jamil.j.nimeh@oracle.com> Co-authored-by: John Jiang <sha.jiang@oracle.com> Co-authored-by: Rajan Halade <rajan.halade@oracle.com> Co-authored-by: Sibabrata Sahoo <sibabrata.sahoo@oracle.com> Co-authored-by: Valerie Peng <valerie.peng@oracle.com> Co-authored-by: Weijun Wang <weijun.wang@oracle.com> Reviewed-by: ascarpino, coffeys, dfuchs, jjiang, jnimeh, mullan, rhalade, ssahoo, valeriep, weijun, wetmore, xuelei
346 lines
13 KiB
Java
346 lines
13 KiB
Java
/*
|
|
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
// SunJSSE does not support dynamic system properties, no way to re-use
|
|
// system properties in samevm/agentvm mode.
|
|
|
|
/*
|
|
* @test
|
|
* @bug 4416068 4478803 4479736
|
|
* @summary 4273544 JSSE request for function forceV3ClientHello()
|
|
* 4479736 setEnabledProtocols API does not work correctly
|
|
* 4478803 Need APIs to determine the protocol versions used in an SSL
|
|
* session
|
|
* 4701722 protocol mismatch exceptions should be consistent between
|
|
* SSLv3 and TLSv1
|
|
* @run main/othervm TestEnabledProtocols
|
|
* @author Ram Marti
|
|
*/
|
|
|
|
import java.io.*;
|
|
import java.net.*;
|
|
import java.util.*;
|
|
import java.security.*;
|
|
import javax.net.ssl.*;
|
|
import java.security.cert.*;
|
|
|
|
public class TestEnabledProtocols {
|
|
|
|
/*
|
|
* For each of the valid protocols combinations, start a server thread
|
|
* that sets up an SSLServerSocket supporting that protocol. Then run
|
|
* a client thread that attemps to open a connection with all
|
|
* possible protocol combinataion. Verify that we get handshake
|
|
* exceptions correctly. Whenever the connection is established
|
|
* successfully, verify that the negotiated protocol was correct.
|
|
* See results file in this directory for complete results.
|
|
*/
|
|
|
|
static final String[][] protocolStrings = {
|
|
{"TLSv1"},
|
|
{"TLSv1", "SSLv2Hello"},
|
|
{"TLSv1", "SSLv3"},
|
|
{"SSLv3", "SSLv2Hello"},
|
|
{"SSLv3"},
|
|
{"TLSv1", "SSLv3", "SSLv2Hello"}
|
|
};
|
|
|
|
static final boolean [][] eXceptionArray = {
|
|
// Do we expect exception? Protocols supported by the server
|
|
{ false, true, false, true, true, true }, // TLSv1
|
|
{ false, false, false, true, true, false}, // TLSv1,SSLv2Hello
|
|
{ false, true, false, true, false, true }, // TLSv1,SSLv3
|
|
{ true, true, false, false, false, false}, // SSLv3, SSLv2Hello
|
|
{ true, true, false, true, false, true }, // SSLv3
|
|
{ false, false, false, false, false, false } // TLSv1,SSLv3,SSLv2Hello
|
|
};
|
|
|
|
static final String[][] protocolSelected = {
|
|
// TLSv1
|
|
{ "TLSv1", null, "TLSv1", null, null, null },
|
|
|
|
// TLSv1,SSLv2Hello
|
|
{ "TLSv1", "TLSv1", "TLSv1", null, null, "TLSv1"},
|
|
|
|
// TLSv1,SSLv3
|
|
{ "TLSv1", null, "TLSv1", null, "SSLv3", null },
|
|
|
|
// SSLv3, SSLv2Hello
|
|
{ null, null, "SSLv3", "SSLv3", "SSLv3", "SSLv3"},
|
|
|
|
// SSLv3
|
|
{ null, null, "SSLv3", null, "SSLv3", null },
|
|
|
|
// TLSv1,SSLv3,SSLv2Hello
|
|
{ "TLSv1", "TLSv1", "TLSv1", "SSLv3", "SSLv3", "TLSv1" }
|
|
|
|
};
|
|
|
|
/*
|
|
* Where do we find the keystores?
|
|
*/
|
|
final static String pathToStores = "../etc";
|
|
static String passwd = "passphrase";
|
|
static String keyStoreFile = "keystore";
|
|
static String trustStoreFile = "truststore";
|
|
|
|
/*
|
|
* Is the server ready to serve?
|
|
*/
|
|
volatile static boolean serverReady = false;
|
|
|
|
/*
|
|
* Turn on SSL debugging?
|
|
*/
|
|
final static boolean debug = false;
|
|
|
|
// use any free port by default
|
|
volatile int serverPort = 0;
|
|
|
|
volatile Exception clientException = null;
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
// reset the security property to make sure that the algorithms
|
|
// and keys used in this test are not disabled.
|
|
Security.setProperty("jdk.tls.disabledAlgorithms", "");
|
|
|
|
String keyFilename =
|
|
System.getProperty("test.src", "./") + "/" + pathToStores +
|
|
"/" + keyStoreFile;
|
|
String trustFilename =
|
|
System.getProperty("test.src", "./") + "/" + pathToStores +
|
|
"/" + trustStoreFile;
|
|
|
|
System.setProperty("javax.net.ssl.keyStore", keyFilename);
|
|
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
|
|
System.setProperty("javax.net.ssl.trustStore", trustFilename);
|
|
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
|
|
|
|
if (debug)
|
|
System.setProperty("javax.net.debug", "all");
|
|
|
|
new TestEnabledProtocols();
|
|
}
|
|
|
|
TestEnabledProtocols() throws Exception {
|
|
/*
|
|
* Start the tests.
|
|
*/
|
|
SSLServerSocketFactory sslssf =
|
|
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
|
SSLServerSocket sslServerSocket =
|
|
(SSLServerSocket) sslssf.createServerSocket(serverPort);
|
|
serverPort = sslServerSocket.getLocalPort();
|
|
// sslServerSocket.setNeedClientAuth(true);
|
|
|
|
for (int i = 0; i < protocolStrings.length; i++) {
|
|
String [] serverProtocols = protocolStrings[i];
|
|
startServer ss = new startServer(serverProtocols,
|
|
sslServerSocket, protocolStrings.length);
|
|
ss.setDaemon(true);
|
|
ss.start();
|
|
for (int j = 0; j < protocolStrings.length; j++) {
|
|
String [] clientProtocols = protocolStrings[j];
|
|
startClient sc = new startClient(
|
|
clientProtocols, serverProtocols,
|
|
eXceptionArray[i][j], protocolSelected[i][j]);
|
|
sc.start();
|
|
sc.join();
|
|
if (clientException != null) {
|
|
ss.requestStop();
|
|
throw clientException;
|
|
}
|
|
}
|
|
ss.requestStop();
|
|
System.out.println("Waiting for the server to complete");
|
|
ss.join();
|
|
}
|
|
}
|
|
|
|
class startServer extends Thread {
|
|
private String[] enabledP = null;
|
|
SSLServerSocket sslServerSocket = null;
|
|
int numExpConns;
|
|
volatile boolean stopRequested = false;
|
|
|
|
public startServer(String[] enabledProtocols,
|
|
SSLServerSocket sslServerSocket,
|
|
int numExpConns) {
|
|
super("Server Thread");
|
|
serverReady = false;
|
|
enabledP = enabledProtocols;
|
|
this.sslServerSocket = sslServerSocket;
|
|
sslServerSocket.setEnabledProtocols(enabledP);
|
|
this.numExpConns = numExpConns;
|
|
}
|
|
|
|
public void requestStop() {
|
|
stopRequested = true;
|
|
}
|
|
|
|
public void run() {
|
|
int conns = 0;
|
|
while (!stopRequested) {
|
|
SSLSocket socket = null;
|
|
try {
|
|
serverReady = true;
|
|
socket = (SSLSocket)sslServerSocket.accept();
|
|
conns++;
|
|
|
|
// set ready to false. this is just to make the
|
|
// client wait and synchronise exception messages
|
|
serverReady = false;
|
|
socket.startHandshake();
|
|
SSLSession session = socket.getSession();
|
|
session.invalidate();
|
|
|
|
InputStream in = socket.getInputStream();
|
|
OutputStream out = socket.getOutputStream();
|
|
out.write(280);
|
|
in.read();
|
|
|
|
socket.close();
|
|
// sleep for a while so that the server thread can be
|
|
// stopped
|
|
Thread.sleep(30);
|
|
} catch (SSLHandshakeException se) {
|
|
// ignore it; this is part of the testing
|
|
// log it for debugging
|
|
System.out.println("Server SSLHandshakeException:");
|
|
se.printStackTrace(System.out);
|
|
} catch (java.io.InterruptedIOException ioe) {
|
|
// must have been interrupted, no harm
|
|
break;
|
|
} catch (java.lang.InterruptedException ie) {
|
|
// must have been interrupted, no harm
|
|
break;
|
|
} catch (SSLException ssle) {
|
|
// The client side may have closed the socket.
|
|
System.out.println("Server SSLException:");
|
|
ssle.printStackTrace(System.out);
|
|
} catch (Exception e) {
|
|
System.out.println("Server exception:");
|
|
e.printStackTrace(System.out);
|
|
throw new RuntimeException(e);
|
|
} finally {
|
|
try {
|
|
if (socket != null) {
|
|
socket.close();
|
|
}
|
|
} catch (IOException e) {
|
|
// ignore
|
|
}
|
|
}
|
|
if (conns >= numExpConns) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void showProtocols(String name, String[] protocols) {
|
|
System.out.println("Enabled protocols on the " + name + " are: " + Arrays.asList(protocols));
|
|
}
|
|
|
|
class startClient extends Thread {
|
|
boolean hsCompleted = false;
|
|
boolean exceptionExpected = false;
|
|
private String[] enabledP = null;
|
|
private String[] serverP = null; // used to print the result
|
|
private String protocolToUse = null;
|
|
|
|
startClient(String[] enabledProtocol,
|
|
String[] serverP,
|
|
boolean eXception,
|
|
String protocol) throws Exception {
|
|
super("Client Thread");
|
|
this.enabledP = enabledProtocol;
|
|
this.serverP = serverP;
|
|
this.exceptionExpected = eXception;
|
|
this.protocolToUse = protocol;
|
|
}
|
|
|
|
public void run() {
|
|
SSLSocket sslSocket = null;
|
|
try {
|
|
while (!serverReady) {
|
|
Thread.sleep(50);
|
|
}
|
|
System.out.flush();
|
|
System.out.println("=== Starting new test run ===");
|
|
showProtocols("server", serverP);
|
|
showProtocols("client", enabledP);
|
|
|
|
SSLSocketFactory sslsf =
|
|
(SSLSocketFactory)SSLSocketFactory.getDefault();
|
|
sslSocket = (SSLSocket)
|
|
sslsf.createSocket("localhost", serverPort);
|
|
sslSocket.setEnabledProtocols(enabledP);
|
|
sslSocket.startHandshake();
|
|
|
|
SSLSession session = sslSocket.getSession();
|
|
session.invalidate();
|
|
String protocolName = session.getProtocol();
|
|
System.out.println("Protocol name after getSession is " +
|
|
protocolName);
|
|
|
|
if (protocolName.equals(protocolToUse)) {
|
|
System.out.println("** Success **");
|
|
} else {
|
|
System.out.println("** FAILURE ** ");
|
|
throw new RuntimeException
|
|
("expected protocol " + protocolToUse +
|
|
" but using " + protocolName);
|
|
}
|
|
|
|
InputStream in = sslSocket.getInputStream();
|
|
OutputStream out = sslSocket.getOutputStream();
|
|
in.read();
|
|
out.write(280);
|
|
|
|
sslSocket.close();
|
|
|
|
} catch (SSLHandshakeException e) {
|
|
if (!exceptionExpected) {
|
|
System.out.println("Client got UNEXPECTED SSLHandshakeException:");
|
|
e.printStackTrace(System.out);
|
|
System.out.println("** FAILURE **");
|
|
clientException = e;
|
|
} else {
|
|
System.out.println("Client got expected SSLHandshakeException:");
|
|
e.printStackTrace(System.out);
|
|
System.out.println("** Success **");
|
|
}
|
|
} catch (RuntimeException e) {
|
|
clientException = e;
|
|
} catch (Exception e) {
|
|
System.out.println("Client got UNEXPECTED Exception:");
|
|
e.printStackTrace(System.out);
|
|
System.out.println("** FAILURE **");
|
|
clientException = e;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|