1 /*
   2  * Copyright (c) 2003, 2015, 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.*;
  25 import java.net.*;
  26 import java.util.*;
  27 import java.security.*;
  28 import javax.net.*;
  29 import javax.net.ssl.*;
  30 
  31 public class ClientAuth extends PKCS11Test {
  32 
  33     /*
  34      * =============================================================
  35      * Set the various variables needed for the tests, then
  36      * specify what tests to run on each side.
  37      */
  38 
  39     private static Provider provider;
  40     private static final String NSS_PWD = "test12";
  41     private static final String JKS_PWD = "passphrase";
  42     private static final String SERVER_KS = "server.keystore";
  43     private static final String TS = "truststore";
  44     private static String p11config;
  45 
  46     private static String DIR = System.getProperty("DIR");
  47 
  48     /*
  49      * Should we run the client or server in a separate thread?
  50      * Both sides can throw exceptions, but do you have a preference
  51      * as to which side should be the main thread.
  52      */
  53     static boolean separateServerThread = false;
  54 
  55     /*
  56      * Is the server ready to serve?
  57      */
  58     volatile static boolean serverReady = false;
  59 
  60     /*
  61      * Turn on SSL debugging?
  62      */
  63     static boolean debug = false;
  64 
  65     /*
  66      * If the client or server is doing some kind of object creation
  67      * that the other side depends on, and that thread prematurely
  68      * exits, you may experience a hang.  The test harness will
  69      * terminate all hung threads after its timeout has expired,
  70      * currently 3 minutes by default, but you might try to be
  71      * smart about it....
  72      */
  73 
  74     /*
  75      * Define the server side of the test.
  76      *
  77      * If the server prematurely exits, serverReady will be set to true
  78      * to avoid infinite hangs.
  79      */
  80     void doServerSide() throws Exception {
  81 
  82         SSLContext ctx = SSLContext.getInstance("TLS");
  83         char[] passphrase = JKS_PWD.toCharArray();
  84 
  85         // server gets KeyStore from JKS keystore
  86         KeyStore ks = KeyStore.getInstance("JKS");
  87         ks.load(new FileInputStream(new File(DIR, SERVER_KS)), passphrase);
  88         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
  89         kmf.init(ks, passphrase);
  90 
  91         // server gets TrustStore from PKCS#11 token
  92 /*
  93         passphrase = NSS_PWD.toCharArray();
  94         KeyStore ts = KeyStore.getInstance("PKCS11", "SunPKCS11-nss");
  95         ts.load(null, passphrase);
  96         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
  97         tmf.init(ts);
  98 */
  99 
 100         //ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 101         ctx.init(kmf.getKeyManagers(), null, null);
 102         ServerSocketFactory ssf = ctx.getServerSocketFactory();
 103         SSLServerSocket sslServerSocket = (SSLServerSocket)
 104                                 ssf.createServerSocket(serverPort);
 105         sslServerSocket.setNeedClientAuth(true);
 106         serverPort = sslServerSocket.getLocalPort();
 107         System.out.println("serverPort = " + serverPort);
 108 
 109         /*
 110          * Signal Client, we're ready for his connect.
 111          */
 112         serverReady = true;
 113 
 114         SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
 115         InputStream sslIS = sslSocket.getInputStream();
 116         OutputStream sslOS = sslSocket.getOutputStream();
 117 
 118         sslIS.read();
 119         sslOS.write(85);
 120         sslOS.flush();
 121 
 122         sslSocket.close();
 123     }
 124 
 125     /*
 126      * Define the client side of the test.
 127      *
 128      * If the server prematurely exits, serverReady will be set to true
 129      * to avoid infinite hangs.
 130      */
 131     void doClientSide() throws Exception {
 132 
 133         /*
 134          * Wait for server to get started.
 135          */
 136         while (!serverReady) {
 137             Thread.sleep(50);
 138         }
 139 
 140         SSLContext ctx = SSLContext.getInstance("TLS");
 141         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 142 
 143         // client gets KeyStore from PKCS#11 token,
 144         // and gets TrustStore from JKS KeyStore (using system properties)
 145         char[] passphrase = NSS_PWD.toCharArray();
 146         KeyStore ks = KeyStore.getInstance("PKCS11", "SunPKCS11-nss");
 147         ks.load(null, passphrase);
 148 
 149         kmf = KeyManagerFactory.getInstance("SunX509");
 150         kmf.init(ks, passphrase);
 151         ctx.init(kmf.getKeyManagers(), null, null);
 152 
 153         SSLSocketFactory sslsf = ctx.getSocketFactory();
 154         SSLSocket sslSocket = (SSLSocket)
 155             sslsf.createSocket("localhost", serverPort);
 156 
 157         if (clientProtocol != null) {
 158             sslSocket.setEnabledProtocols(new String[] {clientProtocol});
 159         }
 160 
 161         if (clientCiperSuite != null) {
 162             sslSocket.setEnabledCipherSuites(new String[] {clientCiperSuite});
 163         }
 164 
 165         InputStream sslIS = sslSocket.getInputStream();
 166         OutputStream sslOS = sslSocket.getOutputStream();
 167 
 168         sslOS.write(280);
 169         sslOS.flush();
 170         sslIS.read();
 171 
 172         sslSocket.close();
 173     }
 174 
 175     /*
 176      * =============================================================
 177      * The remainder is just support stuff
 178      */
 179 
 180     // use any free port by default
 181     volatile int serverPort = 0;
 182 
 183     volatile Exception serverException = null;
 184     volatile Exception clientException = null;
 185 
 186     private static String clientProtocol = null;
 187     private static String clientCiperSuite = null;
 188 
 189     private static void parseArguments(String[] args) {
 190         if (args.length > 0) {
 191             clientProtocol = args[0];
 192         }
 193 
 194         if (args.length > 1) {
 195             clientCiperSuite = args[1];
 196         }
 197     }
 198 
 199     public static void main(String[] args) throws Exception {
 200         // Get the customized arguments.
 201         parseArguments(args);
 202         main(new ClientAuth());
 203     }
 204 
 205     public void main(Provider p) throws Exception {
 206         // SSL RSA client auth currently needs an RSA cipher
 207         // (cf. NONEwithRSA hack), which is currently not available in
 208         // open builds.
 209         try {
 210             javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding", p);
 211         } catch (GeneralSecurityException e) {
 212             System.out.println("Not supported by provider, skipping");
 213             return;
 214         }
 215 
 216         this.provider = p;
 217 
 218         System.setProperty("javax.net.ssl.trustStore",
 219                                         new File(DIR, TS).toString());
 220         System.setProperty("javax.net.ssl.trustStoreType", "JKS");
 221         System.setProperty("javax.net.ssl.trustStoreProvider", "SUN");
 222         System.setProperty("javax.net.ssl.trustStorePassword", JKS_PWD);
 223 
 224         // perform Security.addProvider of P11 provider
 225         Provider p2 = p.configure(System.getProperty("CUSTOM_P11_CONFIG"));
 226         if (p2 != null) {
 227             Security.addProvider(p2);
 228         } else {
 229             throw new Exception("Error: PKCS11 provider configuration failed");
 230         }
 231 
 232         if (debug) {
 233             System.setProperty("javax.net.debug", "all");
 234         }
 235 
 236         /*
 237          * Start the tests.
 238          */
 239         go();
 240     }
 241 
 242     Thread clientThread = null;
 243     Thread serverThread = null;
 244 
 245     /*
 246      * Fork off the other side, then do your work.
 247      */
 248     private void go() throws Exception {
 249         try {
 250             if (separateServerThread) {
 251                 startServer(true);
 252                 startClient(false);
 253             } else {
 254                 startClient(true);
 255                 startServer(false);
 256             }
 257         } catch (Exception e) {
 258             //swallow for now.  Show later
 259         }
 260 
 261         /*
 262          * Wait for other side to close down.
 263          */
 264         if (separateServerThread) {
 265             serverThread.join();
 266         } else {
 267             clientThread.join();
 268         }
 269 
 270         /*
 271          * When we get here, the test is pretty much over.
 272          * Which side threw the error?
 273          */
 274         Exception local;
 275         Exception remote;
 276         String whichRemote;
 277 
 278         if (separateServerThread) {
 279             remote = serverException;
 280             local = clientException;
 281             whichRemote = "server";
 282         } else {
 283             remote = clientException;
 284             local = serverException;
 285             whichRemote = "client";
 286         }
 287 
 288         /*
 289          * If both failed, return the curthread's exception, but also
 290          * print the remote side Exception
 291          */
 292         if ((local != null) && (remote != null)) {
 293             System.out.println(whichRemote + " also threw:");
 294             remote.printStackTrace();
 295             System.out.println();
 296             throw local;
 297         }
 298 
 299         if (remote != null) {
 300             throw remote;
 301         }
 302 
 303         if (local != null) {
 304             throw local;
 305         }
 306     }
 307 
 308     void startServer(boolean newThread) throws Exception {
 309         if (newThread) {
 310             serverThread = new Thread() {
 311                 public void run() {
 312                     try {
 313                         doServerSide();
 314                     } catch (Exception e) {
 315                         /*
 316                          * Our server thread just died.
 317                          *
 318                          * Release the client, if not active already...
 319                          */
 320                         System.err.println("Server died...");
 321                         serverReady = true;
 322                         serverException = e;
 323                     }
 324                 }
 325             };
 326             serverThread.start();
 327         } else {
 328             try {
 329                 doServerSide();
 330             } catch (Exception e) {
 331                 serverException = e;
 332             } finally {
 333                 serverReady = true;
 334             }
 335         }
 336     }
 337 
 338     void startClient(boolean newThread) throws Exception {
 339         if (newThread) {
 340             clientThread = new Thread() {
 341                 public void run() {
 342                     try {
 343                         doClientSide();
 344                     } catch (Exception e) {
 345                         /*
 346                          * Our client thread just died.
 347                          */
 348                         System.err.println("Client died...");
 349                         clientException = e;
 350                     }
 351                 }
 352             };
 353             clientThread.start();
 354         } else {
 355             try {
 356                 doClientSide();
 357             } catch (Exception e) {
 358                 clientException = e;
 359             }
 360         }
 361     }
 362 }