Path: blob/master/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java
41161 views
/*1* Copyright (c) 2016, 2019, 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*/2223//24// SunJSSE does not support dynamic system properties, no way to re-use25// system properties in samevm/agentvm mode.26//2728/*29* @test30* @bug 814456631* @summary Custom HostnameVerifier disables SNI extension32* @run main/othervm ImpactOnSNI33*/3435import java.io.*;36import java.net.*;37import javax.net.ssl.*;3839public class ImpactOnSNI {4041/*42* =============================================================43* Set the various variables needed for the tests, then44* specify what tests to run on each side.45*/4647/*48* Should we run the client or server in a separate thread?49* Both sides can throw exceptions, but do you have a preference50* as to which side should be the main thread.51*/52private static final boolean separateServerThread = true;5354/*55* Where do we find the keystores?56*/57private static final String pathToStores =58"../../../../../../javax/net/ssl/etc";59private static final String keyStoreFile = "keystore";60private static final String trustStoreFile = "truststore";61private static final String passwd = "passphrase";6263/*64* Is the server ready to serve?65*/66private static volatile boolean serverReady = false;6768/*69* Is the connection ready to close?70*/71private static volatile boolean closeReady = false;7273/*74* Turn on SSL debugging?75*/76private static final boolean debug = false;7778/*79* Message posted80*/81private static final String postMsg = "HTTP post on a https server";8283/*84* the fully qualified domain name of localhost85*/86private static String hostname = null;8788/*89* If the client or server is doing some kind of object creation90* that the other side depends on, and that thread prematurely91* exits, you may experience a hang. The test harness will92* terminate all hung threads after its timeout has expired,93* currently 3 minutes by default, but you might try to be94* smart about it....95*/9697private SSLServerSocket createServerSocket(SSLServerSocketFactory sslssf)98throws Exception {99SSLServerSocket sslServerSocket =100(SSLServerSocket)sslssf.createServerSocket();101InetAddress localHost = InetAddress.getLocalHost();102InetSocketAddress address = new InetSocketAddress(localHost, serverPort);103sslServerSocket.bind(address);104return sslServerSocket;105}106107/*108* Define the server side of the test.109*110* If the server prematurely exits, serverReady will be set to true111* to avoid infinite hangs.112*/113private void doServerSide() throws Exception {114SSLServerSocketFactory sslssf =115(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();116try (SSLServerSocket sslServerSocket = createServerSocket(sslssf)) {117118serverPort = sslServerSocket.getLocalPort();119120/*121* Signal Client, we're ready for his connect.122*/123serverReady = true;124125/*126* Accept connections127*/128try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {129InputStream sslIS = sslSocket.getInputStream();130OutputStream sslOS = sslSocket.getOutputStream();131BufferedReader br =132new BufferedReader(new InputStreamReader(sslIS));133PrintStream ps = new PrintStream(sslOS);134135// process HTTP POST request from client136System.out.println("status line: " + br.readLine());137String msg = null;138while ((msg = br.readLine()) != null && msg.length() > 0);139140msg = br.readLine();141if (msg.equals(postMsg)) {142ps.println("HTTP/1.1 200 OK\n\n");143} else {144ps.println("HTTP/1.1 500 Not OK\n\n");145}146ps.flush();147148ExtendedSSLSession session =149(ExtendedSSLSession)sslSocket.getSession();150if (session.getRequestedServerNames().isEmpty()) {151throw new Exception("No expected Server Name Indication");152}153154// close the socket155while (!closeReady) {156Thread.sleep(50);157}158}159}160}161162/*163* Define the client side of the test.164*165* If the server prematurely exits, serverReady will be set to true166* to avoid infinite hangs.167*/168private void doClientSide() throws Exception {169/*170* Wait for server to get started.171*/172while (!serverReady) {173Thread.sleep(50);174}175176// Send HTTP POST request to server177URL url = new URL("https://" + hostname + ":" + serverPort);178179HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());180HttpsURLConnection http = (HttpsURLConnection)url.openConnection();181http.setDoOutput(true);182183http.setRequestMethod("POST");184PrintStream ps = new PrintStream(http.getOutputStream());185try {186ps.println(postMsg);187ps.flush();188if (http.getResponseCode() != 200) {189throw new RuntimeException("test Failed");190}191} finally {192ps.close();193http.disconnect();194closeReady = true;195}196}197198private static class NameVerifier implements HostnameVerifier {199public boolean verify(String hostname, SSLSession session) {200return true;201}202}203204/*205* =============================================================206* The remainder is just support stuff207*/208209// use any free port by default210private volatile int serverPort = 0;211212private volatile Exception serverException = null;213private volatile Exception clientException = null;214215public static void main(String[] args) throws Exception {216String keyFilename =217System.getProperty("test.src", "./") + "/" + pathToStores +218"/" + keyStoreFile;219String trustFilename =220System.getProperty("test.src", "./") + "/" + pathToStores +221"/" + trustStoreFile;222223System.setProperty("javax.net.ssl.keyStore", keyFilename);224System.setProperty("javax.net.ssl.keyStorePassword", passwd);225System.setProperty("javax.net.ssl.trustStore", trustFilename);226System.setProperty("javax.net.ssl.trustStorePassword", passwd);227228if (debug) {229System.setProperty("javax.net.debug", "all");230}231232try {233hostname = InetAddress.getLocalHost().getCanonicalHostName();234} catch (UnknownHostException uhe) {235System.out.println(236"Ignore the test as the local hostname cannot be determined");237238return;239}240241System.out.println(242"The fully qualified domain name of the local host is " +243hostname);244// Ignore the test if the hostname does not sound like a domain name.245if ((hostname == null) || hostname.isEmpty() ||246!hostname.contains(".") || hostname.endsWith(".") ||247hostname.startsWith("localhost") ||248Character.isDigit(hostname.charAt(hostname.length() - 1))) {249250System.out.println("Ignore the test as the local hostname " +251"cannot be determined as fully qualified domain name");252253return;254}255256/*257* Start the tests.258*/259new ImpactOnSNI();260}261262private Thread clientThread = null;263private Thread serverThread = null;264265/*266* Primary constructor, used to drive remainder of the test.267*268* Fork off the other side, then do your work.269*/270ImpactOnSNI() throws Exception {271Exception startException = null;272try {273if (separateServerThread) {274startServer(true);275startClient(false);276} else {277startClient(true);278startServer(false);279}280} catch (Exception e) {281startException = e;282}283284/*285* Wait for other side to close down.286*/287if (separateServerThread) {288if (serverThread != null) {289serverThread.join();290}291} else {292if (clientThread != null) {293clientThread.join();294}295}296297/*298* When we get here, the test is pretty much over.299* Which side threw the error?300*/301Exception local;302Exception remote;303304if (separateServerThread) {305remote = serverException;306local = clientException;307} else {308remote = clientException;309local = serverException;310}311312Exception exception = null;313314/*315* Check various exception conditions.316*/317if ((local != null) && (remote != null)) {318// If both failed, return the curthread's exception.319local.initCause(remote);320exception = local;321} else if (local != null) {322exception = local;323} else if (remote != null) {324exception = remote;325} else if (startException != null) {326exception = startException;327}328329/*330* If there was an exception *AND* a startException,331* output it.332*/333if (exception != null) {334if (exception != startException && startException != null) {335exception.addSuppressed(startException);336}337throw exception;338}339340// Fall-through: no exception to throw!341}342343private void startServer(boolean newThread) throws Exception {344if (newThread) {345serverThread = new Thread() {346@Override347public void run() {348try {349doServerSide();350} catch (Exception e) {351/*352* Our server thread just died.353*354* Release the client, if not active already...355*/356System.err.println("Server died...");357serverReady = true;358serverException = e;359}360}361};362serverThread.start();363} else {364try {365doServerSide();366} catch (Exception e) {367serverException = e;368} finally {369serverReady = true;370}371}372}373374private void startClient(boolean newThread) throws Exception {375if (newThread) {376clientThread = new Thread() {377@Override378public void run() {379try {380doClientSide();381} catch (Exception e) {382/*383* Our client thread just died.384*/385System.err.println("Client died...");386clientException = e;387}388}389};390clientThread.start();391} else {392try {393doClientSide();394} catch (Exception e) {395clientException = e;396}397}398}399}400401402