Path: blob/master/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java
41152 views
/*1* Copyright (c) 2003, 2020, 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 825083929* @summary Improve test template SSLEngineTemplate with SSLContextTemplate30* @build SSLContextTemplate31* @run main/othervm SSLEngineTemplate32*/33import javax.net.ssl.*;34import javax.net.ssl.SSLEngineResult.HandshakeStatus;35import java.nio.ByteBuffer;3637/**38* A SSLEngine usage example which simplifies the presentation39* by removing the I/O and multi-threading concerns.40*41* The test creates two SSLEngines, simulating a client and server.42* The "transport" layer consists two byte buffers: think of them43* as directly connected pipes.44*45* Note, this is a *very* simple example: real code will be much more46* involved. For example, different threading and I/O models could be47* used, transport mechanisms could close unexpectedly, and so on.48*49* When this application runs, notice that several messages50* (wrap/unwrap) pass before any application data is consumed or51* produced.52*/53public class SSLEngineTemplate implements SSLContextTemplate {54protected final SSLEngine clientEngine; // client Engine55protected final ByteBuffer clientOut; // write side of clientEngine56protected final ByteBuffer clientIn; // read side of clientEngine5758protected final SSLEngine serverEngine; // server Engine59protected final ByteBuffer serverOut; // write side of serverEngine60protected final ByteBuffer serverIn; // read side of serverEngine6162// For data transport, this example uses local ByteBuffers. This63// isn't really useful, but the purpose of this example is to show64// SSLEngine concepts, not how to do network transport.65protected final ByteBuffer cTOs; // "reliable" transport client->server66protected final ByteBuffer sTOc; // "reliable" transport server->client6768protected SSLEngineTemplate() throws Exception {69serverEngine = configureServerEngine(70createServerSSLContext().createSSLEngine());7172clientEngine = configureClientEngine(73createClientSSLContext().createSSLEngine());7475// We'll assume the buffer sizes are the same76// between client and server.77SSLSession session = clientEngine.getSession();78int appBufferMax = session.getApplicationBufferSize();79int netBufferMax = session.getPacketBufferSize();8081// We'll make the input buffers a bit bigger than the max needed82// size, so that unwrap()s following a successful data transfer83// won't generate BUFFER_OVERFLOWS.84//85// We'll use a mix of direct and indirect ByteBuffers for86// tutorial purposes only. In reality, only use direct87// ByteBuffers when they give a clear performance enhancement.88clientIn = ByteBuffer.allocate(appBufferMax + 50);89serverIn = ByteBuffer.allocate(appBufferMax + 50);9091cTOs = ByteBuffer.allocateDirect(netBufferMax);92sTOc = ByteBuffer.allocateDirect(netBufferMax);9394clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());95serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());96}9798//99// Protected methods could be used to customize the test case.100//101102/*103* Configure the client side engine.104*/105protected SSLEngine configureClientEngine(SSLEngine clientEngine) {106clientEngine.setUseClientMode(true);107108// Get/set parameters if needed109// SSLParameters paramsClient = clientEngine.getSSLParameters();110// clientEngine.setSSLParameters(paramsClient);111112return clientEngine;113}114115/*116* Configure the server side engine.117*/118protected SSLEngine configureServerEngine(SSLEngine serverEngine) {119serverEngine.setUseClientMode(false);120serverEngine.setNeedClientAuth(true);121122// Get/set parameters if needed123//124// SSLParameters paramsServer = serverEngine.getSSLParameters();125// serverEngine.setSSLParameters(paramsServer);126127return serverEngine;128}129130public static void main(String[] args) throws Exception {131new SSLEngineTemplate().runTest();132}133134//135// Private methods that used to build the common part of the test.136//137138private void runTest() throws Exception {139SSLEngineResult clientResult;140SSLEngineResult serverResult;141142boolean dataDone = false;143while (isOpen(clientEngine) || isOpen(serverEngine)) {144log("=================");145146// client wrap147log("---Client Wrap---");148clientResult = clientEngine.wrap(clientOut, cTOs);149logEngineStatus(clientEngine, clientResult);150runDelegatedTasks(clientEngine);151152// server wrap153log("---Server Wrap---");154serverResult = serverEngine.wrap(serverOut, sTOc);155logEngineStatus(serverEngine, serverResult);156runDelegatedTasks(serverEngine);157158cTOs.flip();159sTOc.flip();160161// client unwrap162log("---Client Unwrap---");163clientResult = clientEngine.unwrap(sTOc, clientIn);164logEngineStatus(clientEngine, clientResult);165runDelegatedTasks(clientEngine);166167// server unwrap168log("---Server Unwrap---");169serverResult = serverEngine.unwrap(cTOs, serverIn);170logEngineStatus(serverEngine, serverResult);171runDelegatedTasks(serverEngine);172173cTOs.compact();174sTOc.compact();175176// After we've transferred all application data between the client177// and server, we close the clientEngine's outbound stream.178// This generates a close_notify handshake message, which the179// server engine receives and responds by closing itself.180if (!dataDone && (clientOut.limit() == serverIn.position()) &&181(serverOut.limit() == clientIn.position())) {182183// A sanity check to ensure we got what was sent.184checkTransfer(serverOut, clientIn);185checkTransfer(clientOut, serverIn);186187log("\tClosing clientEngine's *OUTBOUND*...");188clientEngine.closeOutbound();189logEngineStatus(clientEngine);190191dataDone = true;192log("\tClosing serverEngine's *OUTBOUND*...");193serverEngine.closeOutbound();194logEngineStatus(serverEngine);195}196}197}198199static boolean isOpen(SSLEngine engine) {200return (!engine.isOutboundDone() || !engine.isInboundDone());201}202203private static void logEngineStatus(SSLEngine engine) {204log("\tCurrent HS State: " + engine.getHandshakeStatus());205log("\tisInboundDone() : " + engine.isInboundDone());206log("\tisOutboundDone(): " + engine.isOutboundDone());207}208209private static void logEngineStatus(210SSLEngine engine, SSLEngineResult result) {211log("\tResult Status : " + result.getStatus());212log("\tResult HS Status : " + result.getHandshakeStatus());213log("\tEngine HS Status : " + engine.getHandshakeStatus());214log("\tisInboundDone() : " + engine.isInboundDone());215log("\tisOutboundDone() : " + engine.isOutboundDone());216log("\tMore Result : " + result);217}218219private static void log(String message) {220System.err.println(message);221}222223// If the result indicates that we have outstanding tasks to do,224// go ahead and run them in this thread.225protected static void runDelegatedTasks(SSLEngine engine) throws Exception {226if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {227Runnable runnable;228while ((runnable = engine.getDelegatedTask()) != null) {229log(" running delegated task...");230runnable.run();231}232HandshakeStatus hsStatus = engine.getHandshakeStatus();233if (hsStatus == HandshakeStatus.NEED_TASK) {234throw new Exception(235"handshake shouldn't need additional tasks");236}237logEngineStatus(engine);238}239}240241// Simple check to make sure everything came across as expected.242static void checkTransfer(ByteBuffer a, ByteBuffer b)243throws Exception {244a.flip();245b.flip();246247if (!a.equals(b)) {248throw new Exception("Data didn't transfer cleanly");249} else {250log("\tData transferred cleanly");251}252253a.position(a.limit());254b.position(b.limit());255a.limit(a.capacity());256b.limit(b.capacity());257}258}259260261