Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java
38854 views
/*1* Copyright (c) 2003, 2018, 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// SunJSSE does not support dynamic system properties, no way to re-use24// system properties in samevm/agentvm mode.2526/*27* @test28* @bug 123456729* @summary SSLEngine has not yet caused Solaris kernel to panic30* @run main/othervm SSLEngineTemplate31*/32/**33* A SSLEngine usage example which simplifies the presentation34* by removing the I/O and multi-threading concerns.35*36* The test creates two SSLEngines, simulating a client and server.37* The "transport" layer consists two byte buffers: think of them38* as directly connected pipes.39*40* Note, this is a *very* simple example: real code will be much more41* involved. For example, different threading and I/O models could be42* used, transport mechanisms could close unexpectedly, and so on.43*44* When this application runs, notice that several messages45* (wrap/unwrap) pass before any application data is consumed or46* produced. (For more information, please see the SSL/TLS47* specifications.) There may several steps for a successful handshake,48* so it's typical to see the following series of operations:49*50* client server message51* ====== ====== =======52* wrap() ... ClientHello53* ... unwrap() ClientHello54* ... wrap() ServerHello/Certificate55* unwrap() ... ServerHello/Certificate56* wrap() ... ClientKeyExchange57* wrap() ... ChangeCipherSpec58* wrap() ... Finished59* ... unwrap() ClientKeyExchange60* ... unwrap() ChangeCipherSpec61* ... unwrap() Finished62* ... wrap() ChangeCipherSpec63* ... wrap() Finished64* unwrap() ... ChangeCipherSpec65* unwrap() ... Finished66*/67import javax.net.ssl.*;68import javax.net.ssl.SSLEngineResult.*;69import java.io.*;70import java.security.*;71import java.nio.*;7273public class SSLEngineTemplate {7475/*76* Enables logging of the SSLEngine operations.77*/78private static final boolean logging = true;7980/*81* Enables the JSSE system debugging system property:82*83* -Djavax.net.debug=all84*85* This gives a lot of low-level information about operations underway,86* including specific handshake messages, and might be best examined87* after gaining some familiarity with this application.88*/89private static final boolean debug = false;9091private final SSLContext sslc;9293private SSLEngine clientEngine; // client Engine94private ByteBuffer clientOut; // write side of clientEngine95private ByteBuffer clientIn; // read side of clientEngine9697private SSLEngine serverEngine; // server Engine98private ByteBuffer serverOut; // write side of serverEngine99private ByteBuffer serverIn; // read side of serverEngine100101/*102* For data transport, this example uses local ByteBuffers. This103* isn't really useful, but the purpose of this example is to show104* SSLEngine concepts, not how to do network transport.105*/106private ByteBuffer cTOs; // "reliable" transport client->server107private ByteBuffer sTOc; // "reliable" transport server->client108109/*110* The following is to set up the keystores.111*/112private static final String pathToStores = "../etc";113private static final String keyStoreFile = "keystore";114private static final String trustStoreFile = "truststore";115private static final char[] passphrase = "passphrase".toCharArray();116117private static final String keyFilename =118System.getProperty("test.src", ".") + "/" + pathToStores +119"/" + keyStoreFile;120private static final String trustFilename =121System.getProperty("test.src", ".") + "/" + pathToStores +122"/" + trustStoreFile;123124/*125* Main entry point for this test.126*/127public static void main(String args[]) throws Exception {128if (debug) {129System.setProperty("javax.net.debug", "all");130}131132SSLEngineTemplate test = new SSLEngineTemplate();133test.runTest();134135System.out.println("Test Passed.");136}137138/*139* Create an initialized SSLContext to use for these tests.140*/141public SSLEngineTemplate() throws Exception {142143KeyStore ks = KeyStore.getInstance("JKS");144KeyStore ts = KeyStore.getInstance("JKS");145146ks.load(new FileInputStream(keyFilename), passphrase);147ts.load(new FileInputStream(trustFilename), passphrase);148149KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");150kmf.init(ks, passphrase);151152TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");153tmf.init(ts);154155SSLContext sslCtx = SSLContext.getInstance("TLS");156157sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);158159sslc = sslCtx;160}161162/*163* Run the test.164*165* Sit in a tight loop, both engines calling wrap/unwrap regardless166* of whether data is available or not. We do this until both engines167* report back they are closed.168*169* The main loop handles all of the I/O phases of the SSLEngine's170* lifetime:171*172* initial handshaking173* application data transfer174* engine closing175*176* One could easily separate these phases into separate177* sections of code.178*/179private void runTest() throws Exception {180boolean dataDone = false;181182createSSLEngines();183createBuffers();184185// results from client's last operation186SSLEngineResult clientResult;187188// results from server's last operation189SSLEngineResult serverResult;190191/*192* Examining the SSLEngineResults could be much more involved,193* and may alter the overall flow of the application.194*195* For example, if we received a BUFFER_OVERFLOW when trying196* to write to the output pipe, we could reallocate a larger197* pipe, but instead we wait for the peer to drain it.198*/199Exception clientException = null;200Exception serverException = null;201202while (!isEngineClosed(clientEngine)203|| !isEngineClosed(serverEngine)) {204205log("================");206207try {208clientResult = clientEngine.wrap(clientOut, cTOs);209log("client wrap: ", clientResult);210} catch (Exception e) {211clientException = e;212System.out.println("Client wrap() threw: " + e.getMessage());213}214logEngineStatus(clientEngine);215runDelegatedTasks(clientEngine);216217log("----");218219try {220serverResult = serverEngine.wrap(serverOut, sTOc);221log("server wrap: ", serverResult);222} catch (Exception e) {223serverException = e;224System.out.println("Server wrap() threw: " + e.getMessage());225}226logEngineStatus(serverEngine);227runDelegatedTasks(serverEngine);228229cTOs.flip();230sTOc.flip();231232log("--------");233234try {235clientResult = clientEngine.unwrap(sTOc, clientIn);236log("client unwrap: ", clientResult);237} catch (Exception e) {238clientException = e;239System.out.println("Client unwrap() threw: " + e.getMessage());240}241logEngineStatus(clientEngine);242runDelegatedTasks(clientEngine);243244log("----");245246try {247serverResult = serverEngine.unwrap(cTOs, serverIn);248log("server unwrap: ", serverResult);249} catch (Exception e) {250serverException = e;251System.out.println("Server unwrap() threw: " + e.getMessage());252}253logEngineStatus(serverEngine);254runDelegatedTasks(serverEngine);255256cTOs.compact();257sTOc.compact();258259/*260* After we've transfered all application data between the client261* and server, we close the clientEngine's outbound stream.262* This generates a close_notify handshake message, which the263* server engine receives and responds by closing itself.264*/265if (!dataDone && (clientOut.limit() == serverIn.position()) &&266(serverOut.limit() == clientIn.position())) {267268/*269* A sanity check to ensure we got what was sent.270*/271checkTransfer(serverOut, clientIn);272checkTransfer(clientOut, serverIn);273274log("\tClosing clientEngine's *OUTBOUND*...");275clientEngine.closeOutbound();276logEngineStatus(clientEngine);277278dataDone = true;279log("\tClosing serverEngine's *OUTBOUND*...");280serverEngine.closeOutbound();281logEngineStatus(serverEngine);282}283}284}285286private static void logEngineStatus(SSLEngine engine) {287log("\tCurrent HS State " + engine.getHandshakeStatus().toString());288log("\tisInboundDone(): " + engine.isInboundDone());289log("\tisOutboundDone(): " + engine.isOutboundDone());290}291292/*293* Using the SSLContext created during object creation,294* create/configure the SSLEngines we'll use for this test.295*/296private void createSSLEngines() throws Exception {297/*298* Configure the serverEngine to act as a server in the SSL/TLS299* handshake. Also, require SSL client authentication.300*/301serverEngine = sslc.createSSLEngine();302serverEngine.setUseClientMode(false);303serverEngine.setNeedClientAuth(true);304305// Get/set parameters if needed306SSLParameters paramsServer = serverEngine.getSSLParameters();307serverEngine.setSSLParameters(paramsServer);308309/*310* Similar to above, but using client mode instead.311*/312clientEngine = sslc.createSSLEngine("client", 80);313clientEngine.setUseClientMode(true);314315// Get/set parameters if needed316SSLParameters paramsClient = clientEngine.getSSLParameters();317clientEngine.setSSLParameters(paramsClient);318}319320/*321* Create and size the buffers appropriately.322*/323private void createBuffers() {324325/*326* We'll assume the buffer sizes are the same327* between client and server.328*/329SSLSession session = clientEngine.getSession();330int appBufferMax = session.getApplicationBufferSize();331int netBufferMax = session.getPacketBufferSize();332333/*334* We'll make the input buffers a bit bigger than the max needed335* size, so that unwrap()s following a successful data transfer336* won't generate BUFFER_OVERFLOWS.337*338* We'll use a mix of direct and indirect ByteBuffers for339* tutorial purposes only. In reality, only use direct340* ByteBuffers when they give a clear performance enhancement.341*/342clientIn = ByteBuffer.allocate(appBufferMax + 50);343serverIn = ByteBuffer.allocate(appBufferMax + 50);344345cTOs = ByteBuffer.allocateDirect(netBufferMax);346sTOc = ByteBuffer.allocateDirect(netBufferMax);347348clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());349serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());350}351352/*353* If the result indicates that we have outstanding tasks to do,354* go ahead and run them in this thread.355*/356private static void runDelegatedTasks(SSLEngine engine) throws Exception {357358if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {359Runnable runnable;360while ((runnable = engine.getDelegatedTask()) != null) {361log(" running delegated task...");362runnable.run();363}364HandshakeStatus hsStatus = engine.getHandshakeStatus();365if (hsStatus == HandshakeStatus.NEED_TASK) {366throw new Exception(367"handshake shouldn't need additional tasks");368}369logEngineStatus(engine);370}371}372373private static boolean isEngineClosed(SSLEngine engine) {374return (engine.isOutboundDone() && engine.isInboundDone());375}376377/*378* Simple check to make sure everything came across as expected.379*/380private static void checkTransfer(ByteBuffer a, ByteBuffer b)381throws Exception {382a.flip();383b.flip();384385if (!a.equals(b)) {386throw new Exception("Data didn't transfer cleanly");387} else {388log("\tData transferred cleanly");389}390391a.position(a.limit());392b.position(b.limit());393a.limit(a.capacity());394b.limit(b.capacity());395}396397/*398* Logging code399*/400private static boolean resultOnce = true;401402private static void log(String str, SSLEngineResult result) {403if (!logging) {404return;405}406if (resultOnce) {407resultOnce = false;408System.out.println("The format of the SSLEngineResult is: \n" +409"\t\"getStatus() / getHandshakeStatus()\" +\n" +410"\t\"bytesConsumed() / bytesProduced()\"\n");411}412HandshakeStatus hsStatus = result.getHandshakeStatus();413log(str +414result.getStatus() + "/" + hsStatus + ", " +415result.bytesConsumed() + "/" + result.bytesProduced() +416" bytes");417if (hsStatus == HandshakeStatus.FINISHED) {418log("\t...ready for application data");419}420}421422private static void log(String str) {423if (logging) {424System.out.println(str);425}426}427}428429430