Path: blob/master/test/jdk/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java
41152 views
/*1* Copyright (c) 2004, 2013, 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//24// SunJSSE does not support dynamic system properties, no way to re-use25// system properties in samevm/agentvm mode.26//2728/*29* @test30* @bug 620732231* @summary SSLEngine is returning a premature FINISHED message when doing32* an abbreviated handshake.33* @run main/othervm RehandshakeFinished34* @author Brad Wetmore35*/3637/*38* This test may need some updating if the messages change order.39* Currently I'm expecting that there is a simple renegotiation, with40* each message being contained in a single SSL packet.41*42* ClientHello43* Server Hello44* CCS45* FINISHED46* CCS47* FINISHED48*/4950/**51* A SSLEngine usage example which simplifies the presentation52* by removing the I/O and multi-threading concerns.53*54* The test creates two SSLEngines, simulating a client and server.55* The "transport" layer consists two byte buffers: think of them56* as directly connected pipes.57*58* Note, this is a *very* simple example: real code will be much more59* involved. For example, different threading and I/O models could be60* used, transport mechanisms could close unexpectedly, and so on.61*62* When this application runs, notice that several messages63* (wrap/unwrap) pass before any application data is consumed or64* produced. (For more information, please see the SSL/TLS65* specifications.) There may several steps for a successful handshake,66* so it's typical to see the following series of operations:67*68* client server message69* ====== ====== =======70* wrap() ... ClientHello71* ... unwrap() ClientHello72* ... wrap() ServerHello/Certificate73* unwrap() ... ServerHello/Certificate74* wrap() ... ClientKeyExchange75* wrap() ... ChangeCipherSpec76* wrap() ... Finished77* ... unwrap() ClientKeyExchange78* ... unwrap() ChangeCipherSpec79* ... unwrap() Finished80* ... wrap() ChangeCipherSpec81* ... wrap() Finished82* unwrap() ... ChangeCipherSpec83* unwrap() ... Finished84*/8586import javax.net.ssl.*;87import javax.net.ssl.SSLEngineResult.*;88import java.io.*;89import java.security.*;90import java.nio.*;9192public class RehandshakeFinished {9394/*95* Enables logging of the SSLEngine operations.96*/97private static boolean logging = true;9899/*100* Enables the JSSE system debugging system property:101*102* -Djavax.net.debug=all103*104* This gives a lot of low-level information about operations underway,105* including specific handshake messages, and might be best examined106* after gaining some familiarity with this application.107*/108private static boolean debug = false;109110static private SSLContext sslc;111112private SSLEngine clientEngine; // client Engine113private ByteBuffer clientOut; // write side of clientEngine114private ByteBuffer clientIn; // read side of clientEngine115116private SSLEngine serverEngine; // server Engine117private ByteBuffer serverOut; // write side of serverEngine118private ByteBuffer serverIn; // read side of serverEngine119120/*121* For data transport, this example uses local ByteBuffers. This122* isn't really useful, but the purpose of this example is to show123* SSLEngine concepts, not how to do network transport.124*/125private ByteBuffer cTOs; // "reliable" transport client->server126private ByteBuffer sTOc; // "reliable" transport server->client127128/*129* The following is to set up the keystores.130*/131private static String pathToStores = "../../../../javax/net/ssl/etc";132private static String keyStoreFile = "keystore";133private static String trustStoreFile = "truststore";134private static String passwd = "passphrase";135136private static String keyFilename =137System.getProperty("test.src", "./") + "/" + pathToStores +138"/" + keyStoreFile;139private static String trustFilename =140System.getProperty("test.src", "./") + "/" + pathToStores +141"/" + trustStoreFile;142143private static Exception loadException = null;144145static {146try {147KeyStore ks = KeyStore.getInstance("JKS");148KeyStore ts = KeyStore.getInstance("JKS");149150char[] passphrase = "passphrase".toCharArray();151152ks.load(new FileInputStream(keyFilename), passphrase);153ts.load(new FileInputStream(trustFilename), passphrase);154155KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");156kmf.init(ks, passphrase);157158TrustManagerFactory tmf =159TrustManagerFactory.getInstance("SunX509");160tmf.init(ts);161162SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");163sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);164sslc = sslCtx;165} catch (Exception e) {166loadException = e;167}168}169170/*171* Main entry point for this test.172*/173public static void main(String args[]) throws Exception {174if (debug) {175System.setProperty("javax.net.debug", "all");176}177178if (loadException != null) {179throw loadException;180}181182// Prime the session cache with a good session183// Second connection should be a simple session resumption.184if ((new RehandshakeFinished().runTest()) !=185new RehandshakeFinished().runRehandshake()) {186throw new Exception("Sessions not equivalent");187}188189System.out.println("Test Passed.");190}191192private void checkResult(SSLEngine engine, SSLEngineResult result,193HandshakeStatus rqdHsStatus,194boolean consumed, boolean produced) throws Exception {195196HandshakeStatus hsStatus = result.getHandshakeStatus();197198if (hsStatus == HandshakeStatus.NEED_TASK) {199Runnable runnable;200while ((runnable = engine.getDelegatedTask()) != null) {201runnable.run();202}203hsStatus = engine.getHandshakeStatus();204}205206if (hsStatus != rqdHsStatus) {207throw new Exception("Required " + rqdHsStatus +208", got " + hsStatus);209}210211int bc = result.bytesConsumed();212int bp = result.bytesProduced();213214if (consumed) {215if (bc <= 0) {216throw new Exception("Should have consumed bytes");217}218} else {219if (bc > 0) {220throw new Exception("Should not have consumed bytes");221}222}223224if (produced) {225if (bp <= 0) {226throw new Exception("Should have produced bytes");227}228} else {229if (bp > 0) {230throw new Exception("Should not have produced bytes");231}232}233}234235private SSLSession runRehandshake() throws Exception {236237log("\n\n==============================================");238log("Staring actual test.");239240createSSLEngines();241createBuffers();242SSLEngineResult result;243244log("Client's ClientHello");245checkResult(clientEngine,246clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_UNWRAP,247false, true);248cTOs.flip();249checkResult(serverEngine,250serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_WRAP,251true, false);252cTOs.compact();253254log("Server's ServerHello/ServerHelloDone");255checkResult(serverEngine,256serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP,257false, true);258sTOc.flip();259checkResult(clientEngine,260clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_UNWRAP,261true, false);262sTOc.compact();263264log("Server's CCS");265checkResult(serverEngine,266serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP,267false, true);268sTOc.flip();269checkResult(clientEngine,270clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_UNWRAP,271true, false);272sTOc.compact();273274log("Server's FINISHED");275checkResult(serverEngine,276serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_UNWRAP,277false, true);278sTOc.flip();279checkResult(clientEngine,280clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_WRAP,281true, false);282sTOc.compact();283284log("Client's CCS");285checkResult(clientEngine,286clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_WRAP,287false, true);288cTOs.flip();289checkResult(serverEngine,290serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_UNWRAP,291true, false);292cTOs.compact();293294log("Client's FINISHED should trigger FINISHED messages all around.");295checkResult(clientEngine,296clientEngine.wrap(clientOut, cTOs), HandshakeStatus.FINISHED,297false, true);298cTOs.flip();299checkResult(serverEngine,300serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.FINISHED,301true, false);302cTOs.compact();303304return clientEngine.getSession();305}306307/*308* Run the test.309*310* Sit in a tight loop, both engines calling wrap/unwrap regardless311* of whether data is available or not. We do this until both engines312* report back they are closed.313*314* The main loop handles all of the I/O phases of the SSLEngine's315* lifetime:316*317* initial handshaking318* application data transfer319* engine closing320*321* One could easily separate these phases into separate322* sections of code.323*/324private SSLSession runTest() throws Exception {325boolean dataDone = false;326327createSSLEngines();328createBuffers();329330SSLEngineResult clientResult; // results from client's last operation331SSLEngineResult serverResult; // results from server's last operation332333/*334* Examining the SSLEngineResults could be much more involved,335* and may alter the overall flow of the application.336*337* For example, if we received a BUFFER_OVERFLOW when trying338* to write to the output pipe, we could reallocate a larger339* pipe, but instead we wait for the peer to drain it.340*/341while (!isEngineClosed(clientEngine) ||342!isEngineClosed(serverEngine)) {343344log("================");345346clientResult = clientEngine.wrap(clientOut, cTOs);347log("client wrap: ", clientResult);348runDelegatedTasks(clientResult, clientEngine);349350serverResult = serverEngine.wrap(serverOut, sTOc);351log("server wrap: ", serverResult);352runDelegatedTasks(serverResult, serverEngine);353354cTOs.flip();355sTOc.flip();356357log("----");358359clientResult = clientEngine.unwrap(sTOc, clientIn);360log("client unwrap: ", clientResult);361runDelegatedTasks(clientResult, clientEngine);362363serverResult = serverEngine.unwrap(cTOs, serverIn);364log("server unwrap: ", serverResult);365runDelegatedTasks(serverResult, serverEngine);366367cTOs.compact();368sTOc.compact();369370/*371* After we've transfered all application data between the client372* and server, we close the clientEngine's outbound stream.373* This generates a close_notify handshake message, which the374* server engine receives and responds by closing itself.375*/376if (!dataDone && (clientOut.limit() == serverIn.position()) &&377(serverOut.limit() == clientIn.position())) {378379/*380* A sanity check to ensure we got what was sent.381*/382checkTransfer(serverOut, clientIn);383checkTransfer(clientOut, serverIn);384385log("\tClosing clientEngine's *OUTBOUND*...");386clientEngine.closeOutbound();387dataDone = true;388}389}390391return clientEngine.getSession();392}393394/*395* Using the SSLContext created during object creation,396* create/configure the SSLEngines we'll use for this test.397*/398private void createSSLEngines() throws Exception {399/*400* Configure the serverEngine to act as a server in the SSL/TLS401* handshake. Also, require SSL client authentication.402*/403serverEngine = sslc.createSSLEngine();404serverEngine.setUseClientMode(false);405serverEngine.setNeedClientAuth(true);406407/*408* Similar to above, but using client mode instead.409*/410clientEngine = sslc.createSSLEngine("client", 80);411clientEngine.setUseClientMode(true);412}413414/*415* Create and size the buffers appropriately.416*/417private void createBuffers() {418419/*420* We'll assume the buffer sizes are the same421* between client and server.422*/423SSLSession session = clientEngine.getSession();424int appBufferMax = session.getApplicationBufferSize();425int netBufferMax = session.getPacketBufferSize();426427/*428* We'll make the input buffers a bit bigger than the max needed429* size, so that unwrap()s following a successful data transfer430* won't generate BUFFER_OVERFLOWS.431*432* We'll use a mix of direct and indirect ByteBuffers for433* tutorial purposes only. In reality, only use direct434* ByteBuffers when they give a clear performance enhancement.435*/436clientIn = ByteBuffer.allocate(appBufferMax + 50);437serverIn = ByteBuffer.allocate(appBufferMax + 50);438439cTOs = ByteBuffer.allocateDirect(netBufferMax);440sTOc = ByteBuffer.allocateDirect(netBufferMax);441442clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());443serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());444}445446/*447* If the result indicates that we have outstanding tasks to do,448* go ahead and run them in this thread.449*/450private static void runDelegatedTasks(SSLEngineResult result,451SSLEngine engine) throws Exception {452453if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {454Runnable runnable;455while ((runnable = engine.getDelegatedTask()) != null) {456log("\trunning delegated task...");457runnable.run();458}459HandshakeStatus hsStatus = engine.getHandshakeStatus();460if (hsStatus == HandshakeStatus.NEED_TASK) {461throw new Exception(462"handshake shouldn't need additional tasks");463}464log("\tnew HandshakeStatus: " + hsStatus);465}466}467468private static boolean isEngineClosed(SSLEngine engine) {469return (engine.isOutboundDone() && engine.isInboundDone());470}471472/*473* Simple check to make sure everything came across as expected.474*/475private static void checkTransfer(ByteBuffer a, ByteBuffer b)476throws Exception {477a.flip();478b.flip();479480if (!a.equals(b)) {481throw new Exception("Data didn't transfer cleanly");482} else {483log("\tData transferred cleanly");484}485486a.position(a.limit());487b.position(b.limit());488a.limit(a.capacity());489b.limit(b.capacity());490}491492/*493* Logging code494*/495private static boolean resultOnce = true;496497private static void log(String str, SSLEngineResult result) {498if (!logging) {499return;500}501if (resultOnce) {502resultOnce = false;503System.out.println("The format of the SSLEngineResult is: \n" +504"\t\"getStatus() / getHandshakeStatus()\" +\n" +505"\t\"bytesConsumed() / bytesProduced()\"\n");506}507HandshakeStatus hsStatus = result.getHandshakeStatus();508log(str +509result.getStatus() + "/" + hsStatus + ", " +510result.bytesConsumed() + "/" + result.bytesProduced() +511" bytes");512if (hsStatus == HandshakeStatus.FINISHED) {513log("\t...ready for application data");514}515}516517private static void log(String str) {518if (logging) {519System.out.println(str);520}521}522}523524525