jdk/test/javax/net/ssl/templates/SSLTest.java
changeset 42164 8a725a4f3757
parent 42093 73e29d0ee80c
parent 42163 57aecd16d061
child 42165 49ceb0e3feaa
equal deleted inserted replaced
42093:73e29d0ee80c 42164:8a725a4f3757
     1 /*
       
     2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.io.FileInputStream;
       
    25 import java.io.IOException;
       
    26 import java.io.InputStream;
       
    27 import java.io.OutputStream;
       
    28 import java.net.InetSocketAddress;
       
    29 import java.net.SocketTimeoutException;
       
    30 import java.security.KeyStore;
       
    31 import java.util.Arrays;
       
    32 import java.util.concurrent.CountDownLatch;
       
    33 import java.util.concurrent.TimeUnit;
       
    34 import javax.net.ssl.SSLContext;
       
    35 import javax.net.ssl.SSLServerSocket;
       
    36 import javax.net.ssl.SSLServerSocketFactory;
       
    37 import javax.net.ssl.SSLSocket;
       
    38 import javax.net.ssl.SSLSocketFactory;
       
    39 
       
    40 /**
       
    41  * Helper class for JSSE tests.
       
    42  *
       
    43  * Please run in othervm mode.  SunJSSE does not support dynamic system
       
    44  * properties, no way to re-use system properties in samevm/agentvm mode.
       
    45  */
       
    46 public class SSLTest {
       
    47 
       
    48     public static final String TEST_SRC = System.getProperty("test.src", ".");
       
    49 
       
    50     /*
       
    51      * Where do we find the keystores?
       
    52      */
       
    53     public static final String PATH_TO_STORES = "../etc";
       
    54     public static final String KEY_STORE_FILE = "keystore";
       
    55     public static final String TRUST_STORE_FILE = "truststore";
       
    56     public static final String PASSWORD = "passphrase";
       
    57 
       
    58     public static final int FREE_PORT = 0;
       
    59 
       
    60     // in seconds
       
    61     public static final long CLIENT_SIGNAL_TIMEOUT = 30L;
       
    62     public static final long SERVER_SIGNAL_TIMEOUT = 90L;
       
    63 
       
    64     // in millis
       
    65     public static final int CLIENT_TIMEOUT = 15000;
       
    66     public static final int SERVER_TIMEOUT = 30000;
       
    67 
       
    68     /*
       
    69      * Should we run the client or server in a separate thread?
       
    70      * Both sides can throw exceptions, but do you have a preference
       
    71      * as to which side should be the main thread.
       
    72      */
       
    73     private boolean separateServerThread = false;
       
    74 
       
    75     /*
       
    76      * What's the server port?  Use any free port by default
       
    77      */
       
    78     private volatile int serverPort;
       
    79 
       
    80     private volatile Exception serverException;
       
    81     private volatile Exception clientException;
       
    82 
       
    83     private Thread clientThread;
       
    84     private Thread serverThread;
       
    85 
       
    86     private Peer serverPeer;
       
    87     private Peer clientPeer;
       
    88 
       
    89     private Application serverApplication;
       
    90     private Application clientApplication;
       
    91 
       
    92     private SSLContext context;
       
    93 
       
    94     /*
       
    95      * Is the server ready to serve?
       
    96      */
       
    97     private final CountDownLatch serverReadyCondition = new CountDownLatch(1);
       
    98 
       
    99     /*
       
   100      * Is the client ready to handshake?
       
   101      */
       
   102     private final CountDownLatch clientReadyCondition = new CountDownLatch(1);
       
   103 
       
   104     /*
       
   105      * Is the server done?
       
   106      */
       
   107     private final CountDownLatch serverDoneCondition = new CountDownLatch(1);
       
   108 
       
   109     /*
       
   110      * Is the client done?
       
   111      */
       
   112     private final CountDownLatch clientDoneCondition = new CountDownLatch(1);
       
   113 
       
   114     /*
       
   115      * Public API.
       
   116      */
       
   117 
       
   118     public static interface Peer {
       
   119         void run(SSLTest test) throws Exception;
       
   120     }
       
   121 
       
   122     public static interface Application {
       
   123         void run(SSLSocket socket, SSLTest test) throws Exception;
       
   124     }
       
   125 
       
   126     public static void debug() {
       
   127         debug("ssl");
       
   128     }
       
   129 
       
   130     public static void debug(String mode) {
       
   131         System.setProperty("javax.net.debug", mode);
       
   132     }
       
   133 
       
   134     public static void setup(String keyFilename, String trustFilename,
       
   135             String password) {
       
   136 
       
   137         System.setProperty("javax.net.ssl.keyStore", keyFilename);
       
   138         System.setProperty("javax.net.ssl.keyStorePassword", password);
       
   139         System.setProperty("javax.net.ssl.trustStore", trustFilename);
       
   140         System.setProperty("javax.net.ssl.trustStorePassword", password);
       
   141     }
       
   142 
       
   143     public static void setup() throws Exception {
       
   144         String keyFilename = TEST_SRC + "/" + PATH_TO_STORES + "/"
       
   145                 + KEY_STORE_FILE;
       
   146         String trustFilename = TEST_SRC + "/" + PATH_TO_STORES + "/"
       
   147                 + TRUST_STORE_FILE;
       
   148 
       
   149         setup(keyFilename, trustFilename, PASSWORD);
       
   150     }
       
   151 
       
   152     public static void print(String message, Throwable... errors) {
       
   153         synchronized (System.out) {
       
   154             System.out.println(message);
       
   155             Arrays.stream(errors).forEach(e -> e.printStackTrace(System.out));
       
   156         }
       
   157     }
       
   158 
       
   159     public static KeyStore loadJksKeyStore(String filename, String password)
       
   160             throws Exception {
       
   161 
       
   162         return loadKeyStore(filename, password, "JKS");
       
   163     }
       
   164 
       
   165     public static KeyStore loadKeyStore(String filename, String password,
       
   166             String type) throws Exception {
       
   167 
       
   168         KeyStore keystore = KeyStore.getInstance(type);
       
   169         try (FileInputStream fis = new FileInputStream(filename)) {
       
   170             keystore.load(fis, password.toCharArray());
       
   171         }
       
   172         return keystore;
       
   173     }
       
   174 
       
   175     // Try to accept a connection in 30 seconds.
       
   176     public static SSLSocket accept(SSLServerSocket sslServerSocket)
       
   177             throws IOException {
       
   178 
       
   179         return accept(sslServerSocket, SERVER_TIMEOUT);
       
   180     }
       
   181 
       
   182     public static SSLSocket accept(SSLServerSocket sslServerSocket, int timeout)
       
   183             throws IOException {
       
   184 
       
   185         try {
       
   186             sslServerSocket.setSoTimeout(timeout);
       
   187             return (SSLSocket) sslServerSocket.accept();
       
   188         } catch (SocketTimeoutException ste) {
       
   189             sslServerSocket.close();
       
   190             return null;
       
   191         }
       
   192     }
       
   193 
       
   194     public SSLTest setSeparateServerThread(boolean separateServerThread) {
       
   195         this.separateServerThread = separateServerThread;
       
   196         return this;
       
   197     }
       
   198 
       
   199     public SSLTest setServerPort(int serverPort) {
       
   200         this.serverPort = serverPort;
       
   201         return this;
       
   202     }
       
   203 
       
   204     public int getServerPort() {
       
   205         return serverPort;
       
   206     }
       
   207 
       
   208     public SSLTest setSSLContext(SSLContext context) {
       
   209         this.context = context;
       
   210         return this;
       
   211     }
       
   212 
       
   213     public SSLContext getSSLContext() {
       
   214         return context;
       
   215     }
       
   216 
       
   217     public SSLServerSocketFactory getSSLServerSocketFactory() {
       
   218         if (context != null) {
       
   219             return context.getServerSocketFactory();
       
   220         }
       
   221 
       
   222         return (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
       
   223     }
       
   224 
       
   225     public SSLSocketFactory getSSLSocketFactory() {
       
   226         if (context != null) {
       
   227             return context.getSocketFactory();
       
   228         }
       
   229 
       
   230         return (SSLSocketFactory) SSLSocketFactory.getDefault();
       
   231     }
       
   232 
       
   233     public void signalServerReady() {
       
   234         serverReadyCondition.countDown();
       
   235     }
       
   236 
       
   237     public void signalServerDone() {
       
   238         serverDoneCondition.countDown();
       
   239     }
       
   240 
       
   241     public boolean waitForClientSignal(long timeout, TimeUnit unit)
       
   242             throws InterruptedException {
       
   243 
       
   244         return clientReadyCondition.await(timeout, unit);
       
   245     }
       
   246 
       
   247     public boolean waitForClientSignal() throws InterruptedException {
       
   248         return waitForClientSignal(CLIENT_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
       
   249     }
       
   250 
       
   251     public boolean waitForClientDone(long timeout, TimeUnit unit)
       
   252             throws InterruptedException {
       
   253 
       
   254         return clientDoneCondition.await(timeout, unit);
       
   255     }
       
   256 
       
   257     public boolean waitForClientDone() throws InterruptedException {
       
   258         return waitForClientDone(CLIENT_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
       
   259     }
       
   260 
       
   261     public void signalClientReady() {
       
   262         clientReadyCondition.countDown();
       
   263     }
       
   264 
       
   265     public void signalClientDone() {
       
   266         clientDoneCondition.countDown();
       
   267     }
       
   268 
       
   269     public boolean waitForServerSignal(long timeout, TimeUnit unit)
       
   270             throws InterruptedException {
       
   271 
       
   272         return serverReadyCondition.await(timeout, unit);
       
   273     }
       
   274 
       
   275     public boolean waitForServerSignal() throws InterruptedException {
       
   276         return waitForServerSignal(SERVER_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
       
   277     }
       
   278 
       
   279     public boolean waitForServerDone(long timeout, TimeUnit unit)
       
   280             throws InterruptedException {
       
   281 
       
   282         return serverDoneCondition.await(timeout, unit);
       
   283     }
       
   284 
       
   285     public boolean waitForServerDone() throws InterruptedException {
       
   286         return waitForServerDone(SERVER_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
       
   287     }
       
   288 
       
   289     public SSLTest setServerPeer(Peer serverPeer) {
       
   290         this.serverPeer = serverPeer;
       
   291         return this;
       
   292     }
       
   293 
       
   294     public Peer getServerPeer() {
       
   295         return serverPeer;
       
   296     }
       
   297 
       
   298     public SSLTest setServerApplication(Application serverApplication) {
       
   299         this.serverApplication = serverApplication;
       
   300         return this;
       
   301     }
       
   302 
       
   303     public Application getServerApplication() {
       
   304         return serverApplication;
       
   305     }
       
   306 
       
   307     public SSLTest setClientPeer(Peer clientPeer) {
       
   308         this.clientPeer = clientPeer;
       
   309         return this;
       
   310     }
       
   311 
       
   312     public Peer getClientPeer() {
       
   313         return clientPeer;
       
   314     }
       
   315 
       
   316     public SSLTest setClientApplication(Application clientApplication) {
       
   317         this.clientApplication = clientApplication;
       
   318         return this;
       
   319     }
       
   320 
       
   321     public Application getClientApplication() {
       
   322         return clientApplication;
       
   323     }
       
   324 
       
   325     public void runTest() throws Exception {
       
   326         if (separateServerThread) {
       
   327             startServer(true, this);
       
   328             startClient(false, this);
       
   329             serverThread.join();
       
   330         } else {
       
   331             startClient(true, this);
       
   332             startServer(false, this);
       
   333             clientThread.join();
       
   334         }
       
   335 
       
   336         if (clientException != null || serverException != null) {
       
   337             throw new RuntimeException("Test failed");
       
   338         }
       
   339     }
       
   340 
       
   341     public SSLTest() {
       
   342         serverPeer = (test) -> doServerSide(test);
       
   343         clientPeer = (test) -> doClientSide(test);
       
   344         serverApplication = (socket, test) -> runServerApplication(socket);
       
   345         clientApplication = (socket, test) -> runClientApplication(socket);
       
   346     }
       
   347 
       
   348     /*
       
   349      * Private part.
       
   350      */
       
   351 
       
   352 
       
   353     /*
       
   354      * Define the server side of the test.
       
   355      */
       
   356     private static void doServerSide(SSLTest test) throws Exception {
       
   357         SSLServerSocket sslServerSocket;
       
   358 
       
   359         // kick start the server side service
       
   360         SSLServerSocketFactory sslssf = test.getSSLServerSocketFactory();
       
   361         sslServerSocket = (SSLServerSocket)sslssf.createServerSocket(FREE_PORT);
       
   362 
       
   363         test.setServerPort(sslServerSocket.getLocalPort());
       
   364         print("Server is listening on port " + test.getServerPort());
       
   365 
       
   366         // Signal the client, the server is ready to accept connection.
       
   367         test.signalServerReady();
       
   368 
       
   369         // Try to accept a connection in 30 seconds.
       
   370         SSLSocket sslSocket = accept(sslServerSocket);
       
   371         if (sslSocket == null) {
       
   372             // Ignore the test case if no connection within 30 seconds.
       
   373             print("No incoming client connection in 30 seconds. "
       
   374                     + "Ignore in server side.");
       
   375             return;
       
   376         }
       
   377         print("Server accepted connection");
       
   378 
       
   379         // handle the connection
       
   380         try {
       
   381             // Is it the expected client connection?
       
   382             //
       
   383             // Naughty test cases or third party routines may try to
       
   384             // connection to this server port unintentionally.  In
       
   385             // order to mitigate the impact of unexpected client
       
   386             // connections and avoid intermittent failure, it should
       
   387             // be checked that the accepted connection is really linked
       
   388             // to the expected client.
       
   389             boolean clientIsReady = test.waitForClientSignal();
       
   390 
       
   391             if (clientIsReady) {
       
   392                 // Run the application in server side.
       
   393                 print("Run server application");
       
   394                 test.getServerApplication().run(sslSocket, test);
       
   395             } else {    // Otherwise, ignore
       
   396                 // We don't actually care about plain socket connections
       
   397                 // for TLS communication testing generally.  Just ignore
       
   398                 // the test if the accepted connection is not linked to
       
   399                 // the expected client or the client connection timeout
       
   400                 // in 30 seconds.
       
   401                 print("The client is not the expected one or timeout. "
       
   402                         + "Ignore in server side.");
       
   403             }
       
   404         } finally {
       
   405             sslSocket.close();
       
   406             sslServerSocket.close();
       
   407         }
       
   408 
       
   409         test.signalServerDone();
       
   410     }
       
   411 
       
   412     /*
       
   413      * Define the server side application of the test for the specified socket.
       
   414      */
       
   415     private static void runServerApplication(SSLSocket socket)
       
   416             throws Exception {
       
   417 
       
   418         // here comes the test logic
       
   419         InputStream sslIS = socket.getInputStream();
       
   420         OutputStream sslOS = socket.getOutputStream();
       
   421 
       
   422         sslIS.read();
       
   423         sslOS.write(85);
       
   424         sslOS.flush();
       
   425     }
       
   426 
       
   427     /*
       
   428      * Define the client side of the test.
       
   429      */
       
   430     private static void doClientSide(SSLTest test) throws Exception {
       
   431 
       
   432         // Wait for server to get started.
       
   433         //
       
   434         // The server side takes care of the issue if the server cannot
       
   435         // get started in 90 seconds.  The client side would just ignore
       
   436         // the test case if the serer is not ready.
       
   437         boolean serverIsReady = test.waitForServerSignal();
       
   438         if (!serverIsReady) {
       
   439             print("The server is not ready yet in 90 seconds. "
       
   440                     + "Ignore in client side.");
       
   441             return;
       
   442         }
       
   443 
       
   444         SSLSocketFactory sslsf = test.getSSLSocketFactory();
       
   445         try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
       
   446             try {
       
   447                 sslSocket.connect(
       
   448                         new InetSocketAddress("localhost",
       
   449                                 test.getServerPort()), CLIENT_TIMEOUT);
       
   450                 print("Client connected to server");
       
   451             } catch (IOException ioe) {
       
   452                 // The server side may be impacted by naughty test cases or
       
   453                 // third party routines, and cannot accept connections.
       
   454                 //
       
   455                 // Just ignore the test if the connection cannot be
       
   456                 // established.
       
   457                 print("Cannot make a connection in 15 seconds. "
       
   458                         + "Ignore in client side.", ioe);
       
   459                 return;
       
   460             }
       
   461 
       
   462             // OK, here the client and server get connected.
       
   463 
       
   464             // Signal the server, the client is ready to communicate.
       
   465             test.signalClientReady();
       
   466 
       
   467             // There is still a chance in theory that the server thread may
       
   468             // wait client-ready timeout and then quit.  The chance should
       
   469             // be really rare so we don't consider it until it becomes a
       
   470             // real problem.
       
   471 
       
   472             // Run the application in client side.
       
   473             print("Run client application");
       
   474             test.getClientApplication().run(sslSocket, test);
       
   475         }
       
   476 
       
   477         test.signalClientDone();
       
   478     }
       
   479 
       
   480     /*
       
   481      * Define the client side application of the test for the specified socket.
       
   482      */
       
   483     private static void runClientApplication(SSLSocket socket)
       
   484             throws Exception {
       
   485 
       
   486         InputStream sslIS = socket.getInputStream();
       
   487         OutputStream sslOS = socket.getOutputStream();
       
   488 
       
   489         sslOS.write(280);
       
   490         sslOS.flush();
       
   491         sslIS.read();
       
   492     }
       
   493 
       
   494     private void startServer(boolean newThread, SSLTest test) throws Exception {
       
   495         if (newThread) {
       
   496             serverThread = new Thread() {
       
   497                 @Override
       
   498                 public void run() {
       
   499                     try {
       
   500                         serverPeer.run(test);
       
   501                     } catch (Exception e) {
       
   502                         /*
       
   503                          * Our server thread just died.
       
   504                          *
       
   505                          * Release the client, if not active already...
       
   506                          */
       
   507                         print("Server died ...", e);
       
   508                         serverException = e;
       
   509                     }
       
   510                 }
       
   511             };
       
   512             serverThread.start();
       
   513         } else {
       
   514             try {
       
   515                 serverPeer.run(test);
       
   516             } catch (Exception e) {
       
   517                 print("Server failed ...", e);
       
   518                 serverException = e;
       
   519             }
       
   520         }
       
   521     }
       
   522 
       
   523     private void startClient(boolean newThread, SSLTest test) throws Exception {
       
   524         if (newThread) {
       
   525             clientThread = new Thread() {
       
   526                 @Override
       
   527                 public void run() {
       
   528                     try {
       
   529                         clientPeer.run(test);
       
   530                     } catch (Exception e) {
       
   531                         /*
       
   532                          * Our client thread just died.
       
   533                          */
       
   534                         print("Client died ...", e);
       
   535                         clientException = e;
       
   536                     }
       
   537                 }
       
   538             };
       
   539             clientThread.start();
       
   540         } else {
       
   541             try {
       
   542                 clientPeer.run(test);
       
   543             } catch (Exception e) {
       
   544                 print("Client failed ...", e);
       
   545                 clientException = e;
       
   546             }
       
   547         }
       
   548     }
       
   549 }