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 // SunJSSE does not support dynamic system properties, no way to re-use 25 // system properties in samevm/agentvm mode. 26 27 /* 28 * @test 29 * @bug 1234567 30 * @summary SSLEngine has not yet caused Solaris kernel to panic 31 * @run main/othervm SSLEngineTemplate 32 */ 33 34 /** 35 * A SSLEngine usage example which simplifies the presentation 36 * by removing the I/O and multi-threading concerns. 37 * 38 * The test creates two SSLEngines, simulating a client and server. 39 * The "transport" layer consists two byte buffers: think of them 40 * as directly connected pipes. 41 * 42 * Note, this is a *very* simple example: real code will be much more 43 * involved. For example, different threading and I/O models could be 44 * used, transport mechanisms could close unexpectedly, and so on. 45 * 46 * When this application runs, notice that several messages 47 * (wrap/unwrap) pass before any application data is consumed or 48 * produced. (For more information, please see the SSL/TLS 49 * specifications.) There may several steps for a successful handshake, 50 * so it's typical to see the following series of operations: 51 * 52 * client server message 53 * ====== ====== ======= 54 * wrap() ... ClientHello 55 * ... unwrap() ClientHello 56 * ... wrap() ServerHello/Certificate 57 * unwrap() ... ServerHello/Certificate 58 * wrap() ... ClientKeyExchange 59 * wrap() ... ChangeCipherSpec 60 * wrap() ... Finished 61 * ... unwrap() ClientKeyExchange 62 * ... unwrap() ChangeCipherSpec 63 * ... unwrap() Finished 64 * ... wrap() ChangeCipherSpec 65 * ... wrap() Finished 66 * unwrap() ... ChangeCipherSpec 67 * unwrap() ... Finished 68 */ 69 70 import javax.net.ssl.*; 71 import javax.net.ssl.SSLEngineResult.*; 72 import java.io.*; 73 import java.security.*; 74 import java.nio.*; 75 76 public class SSLEngineTemplate { 77 78 /* 79 * Enables logging of the SSLEngine operations. 80 */ 81 private static final boolean logging = true; 82 83 /* 84 * Enables the JSSE system debugging system property: 85 * 86 * -Djavax.net.debug=all 87 * 88 * This gives a lot of low-level information about operations underway, 89 * including specific handshake messages, and might be best examined 90 * after gaining some familiarity with this application. 91 */ 92 private static final boolean debug = false; 93 94 private final SSLContext sslc; 95 96 private SSLEngine clientEngine; // client Engine 97 private ByteBuffer clientOut; // write side of clientEngine 98 private ByteBuffer clientIn; // read side of clientEngine 99 100 private SSLEngine serverEngine; // server Engine 101 private ByteBuffer serverOut; // write side of serverEngine 102 private ByteBuffer serverIn; // read side of serverEngine 103 104 /* 105 * For data transport, this example uses local ByteBuffers. This 106 * isn't really useful, but the purpose of this example is to show 107 * SSLEngine concepts, not how to do network transport. 108 */ 109 private ByteBuffer cTOs; // "reliable" transport client->server 110 private ByteBuffer sTOc; // "reliable" transport server->client 111 112 /* 113 * The following is to set up the keystores. 114 */ 115 private static final String pathToStores = "../etc"; 116 private static final String keyStoreFile = "keystore"; 117 private static final String trustStoreFile = "truststore"; 118 private static final String passwd = "passphrase"; 119 120 private static final String keyFilename = 121 System.getProperty("test.src", ".") + "/" + pathToStores + 122 "/" + keyStoreFile; 123 private static final String trustFilename = 124 System.getProperty("test.src", ".") + "/" + pathToStores + 125 "/" + trustStoreFile; 126 127 /* 128 * Main entry point for this test. 129 */ 130 public static void main(String args[]) throws Exception { 131 if (debug) { 132 System.setProperty("javax.net.debug", "all"); 133 } 134 135 SSLEngineTemplate test = new SSLEngineTemplate(); 136 test.runTest(); 137 138 System.out.println("Test Passed."); 139 } 140 141 /* 142 * Create an initialized SSLContext to use for these tests. 143 */ 144 public SSLEngineTemplate() throws Exception { 145 146 KeyStore ks = KeyStore.getInstance("JKS"); 147 KeyStore ts = KeyStore.getInstance("JKS"); 148 149 char[] passphrase = "passphrase".toCharArray(); 150 151 ks.load(new FileInputStream(keyFilename), passphrase); 152 ts.load(new FileInputStream(trustFilename), passphrase); 153 154 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 155 kmf.init(ks, passphrase); 156 157 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 158 tmf.init(ts); 159 160 SSLContext sslCtx = SSLContext.getInstance("TLS"); 161 162 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 163 164 sslc = sslCtx; 165 } 166 167 /* 168 * Run the test. 169 * 170 * Sit in a tight loop, both engines calling wrap/unwrap regardless 171 * of whether data is available or not. We do this until both engines 172 * report back they are closed. 173 * 174 * The main loop handles all of the I/O phases of the SSLEngine's 175 * lifetime: 176 * 177 * initial handshaking 178 * application data transfer 179 * engine closing 180 * 181 * One could easily separate these phases into separate 182 * sections of code. 183 */ 184 private void runTest() throws Exception { 185 boolean dataDone = false; 186 187 createSSLEngines(); 188 createBuffers(); 189 190 SSLEngineResult clientResult; // results from client's last operation 191 SSLEngineResult serverResult; // results from server's last operation 192 193 /* 194 * Examining the SSLEngineResults could be much more involved, 195 * and may alter the overall flow of the application. 196 * 197 * For example, if we received a BUFFER_OVERFLOW when trying 198 * to write to the output pipe, we could reallocate a larger 199 * pipe, but instead we wait for the peer to drain it. 200 */ 201 while (!isEngineClosed(clientEngine) || 202 !isEngineClosed(serverEngine)) { 203 204 log("================"); 205 206 clientResult = clientEngine.wrap(clientOut, cTOs); 207 log("client wrap: ", clientResult); 208 runDelegatedTasks(clientResult, clientEngine); 209 210 serverResult = serverEngine.wrap(serverOut, sTOc); 211 log("server wrap: ", serverResult); 212 runDelegatedTasks(serverResult, serverEngine); 213 214 cTOs.flip(); 215 sTOc.flip(); 216 217 log("----"); 218 219 clientResult = clientEngine.unwrap(sTOc, clientIn); 220 log("client unwrap: ", clientResult); 221 runDelegatedTasks(clientResult, clientEngine); 222 223 serverResult = serverEngine.unwrap(cTOs, serverIn); 224 log("server unwrap: ", serverResult); 225 runDelegatedTasks(serverResult, serverEngine); 226 227 cTOs.compact(); 228 sTOc.compact(); 229 230 /* 231 * After we've transfered all application data between the client 232 * and server, we close the clientEngine's outbound stream. 233 * This generates a close_notify handshake message, which the 234 * server engine receives and responds by closing itself. 235 */ 236 if (!dataDone && (clientOut.limit() == serverIn.position()) && 237 (serverOut.limit() == clientIn.position())) { 238 239 /* 240 * A sanity check to ensure we got what was sent. 241 */ 242 checkTransfer(serverOut, clientIn); 243 checkTransfer(clientOut, serverIn); 244 245 log("\tClosing clientEngine's *OUTBOUND*..."); 246 clientEngine.closeOutbound(); 247 dataDone = true; 248 } 249 } 250 } 251 252 /* 253 * Using the SSLContext created during object creation, 254 * create/configure the SSLEngines we'll use for this test. 255 */ 256 private void createSSLEngines() throws Exception { 257 /* 258 * Configure the serverEngine to act as a server in the SSL/TLS 259 * handshake. Also, require SSL client authentication. 260 */ 261 serverEngine = sslc.createSSLEngine(); 262 serverEngine.setUseClientMode(false); 263 serverEngine.setNeedClientAuth(true); 264 265 /* 266 * Similar to above, but using client mode instead. 267 */ 268 clientEngine = sslc.createSSLEngine("client", 80); 269 clientEngine.setUseClientMode(true); 270 } 271 272 /* 273 * Create and size the buffers appropriately. 274 */ 275 private void createBuffers() { 276 277 /* 278 * We'll assume the buffer sizes are the same 279 * between client and server. 280 */ 281 SSLSession session = clientEngine.getSession(); 282 int appBufferMax = session.getApplicationBufferSize(); 283 int netBufferMax = session.getPacketBufferSize(); 284 285 /* 286 * We'll make the input buffers a bit bigger than the max needed 287 * size, so that unwrap()s following a successful data transfer 288 * won't generate BUFFER_OVERFLOWS. 289 * 290 * We'll use a mix of direct and indirect ByteBuffers for 291 * tutorial purposes only. In reality, only use direct 292 * ByteBuffers when they give a clear performance enhancement. 293 */ 294 clientIn = ByteBuffer.allocate(appBufferMax + 50); 295 serverIn = ByteBuffer.allocate(appBufferMax + 50); 296 297 cTOs = ByteBuffer.allocateDirect(netBufferMax); 298 sTOc = ByteBuffer.allocateDirect(netBufferMax); 299 300 clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); 301 serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); 302 } 303 304 /* 305 * If the result indicates that we have outstanding tasks to do, 306 * go ahead and run them in this thread. 307 */ 308 private static void runDelegatedTasks(SSLEngineResult result, 309 SSLEngine engine) throws Exception { 310 311 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 312 Runnable runnable; 313 while ((runnable = engine.getDelegatedTask()) != null) { 314 log("\trunning delegated task..."); 315 runnable.run(); 316 } 317 HandshakeStatus hsStatus = engine.getHandshakeStatus(); 318 if (hsStatus == HandshakeStatus.NEED_TASK) { 319 throw new Exception( 320 "handshake shouldn't need additional tasks"); 321 } 322 log("\tnew HandshakeStatus: " + hsStatus); 323 } 324 } 325 326 private static boolean isEngineClosed(SSLEngine engine) { 327 return (engine.isOutboundDone() && engine.isInboundDone()); 328 } 329 330 /* 331 * Simple check to make sure everything came across as expected. 332 */ 333 private static void checkTransfer(ByteBuffer a, ByteBuffer b) 334 throws Exception { 335 a.flip(); 336 b.flip(); 337 338 if (!a.equals(b)) { 339 throw new Exception("Data didn't transfer cleanly"); 340 } else { 341 log("\tData transferred cleanly"); 342 } 343 344 a.position(a.limit()); 345 b.position(b.limit()); 346 a.limit(a.capacity()); 347 b.limit(b.capacity()); 348 } 349 350 /* 351 * Logging code 352 */ 353 private static boolean resultOnce = true; 354 355 private static void log(String str, SSLEngineResult result) { 356 if (!logging) { 357 return; 358 } 359 if (resultOnce) { 360 resultOnce = false; 361 System.out.println("The format of the SSLEngineResult is: \n" + 362 "\t\"getStatus() / getHandshakeStatus()\" +\n" + 363 "\t\"bytesConsumed() / bytesProduced()\"\n"); 364 } 365 HandshakeStatus hsStatus = result.getHandshakeStatus(); 366 log(str + 367 result.getStatus() + "/" + hsStatus + ", " + 368 result.bytesConsumed() + "/" + result.bytesProduced() + 369 " bytes"); 370 if (hsStatus == HandshakeStatus.FINISHED) { 371 log("\t...ready for application data"); 372 } 373 } 374 375 private static void log(String str) { 376 if (logging) { 377 System.out.println(str); 378 } 379 } 380 }