Path: blob/master/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java
41152 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 820731729* @summary SSLEngine negotiation fail Exception behavior changed from30* fail-fast to fail-lazy31* @run main/othervm SSLEngineFailedALPN32*/33/**34* A SSLEngine usage example which simplifies the presentation35* by removing the I/O and multi-threading concerns.36*37* The test creates two SSLEngines, simulating a client and server.38* The "transport" layer consists two byte buffers: think of them39* as directly connected pipes.40*41* Note, this is a *very* simple example: real code will be much more42* involved. For example, different threading and I/O models could be43* used, transport mechanisms could close unexpectedly, and so on.44*45* When this application runs, notice that several messages46* (wrap/unwrap) pass before any application data is consumed or47* produced. (For more information, please see the SSL/TLS48* specifications.) There may several steps for a successful handshake,49* so it's typical to see the following series of operations:50*51* client server message52* ====== ====== =======53* wrap() ... ClientHello54* ... unwrap() ClientHello55* ... wrap() ServerHello/Certificate56* unwrap() ... ServerHello/Certificate57* wrap() ... ClientKeyExchange58* wrap() ... ChangeCipherSpec59* wrap() ... Finished60* ... unwrap() ClientKeyExchange61* ... unwrap() ChangeCipherSpec62* ... unwrap() Finished63* ... wrap() ChangeCipherSpec64* ... wrap() Finished65* unwrap() ... ChangeCipherSpec66* unwrap() ... Finished67*/68import javax.net.ssl.*;69import javax.net.ssl.SSLEngineResult.*;70import java.io.*;71import java.security.*;72import java.nio.*;7374public class SSLEngineFailedALPN {7576/*77* Enables logging of the SSLEngine operations.78*/79private static final boolean logging = true;8081/*82* Enables the JSSE system debugging system property:83*84* -Djavax.net.debug=all85*86* This gives a lot of low-level information about operations underway,87* including specific handshake messages, and might be best examined88* after gaining some familiarity with this application.89*/90private static final boolean debug = false;9192private final SSLContext sslc;9394private SSLEngine clientEngine; // client Engine95private ByteBuffer clientOut; // write side of clientEngine96private ByteBuffer clientIn; // read side of clientEngine9798private SSLEngine serverEngine; // server Engine99private ByteBuffer serverOut; // write side of serverEngine100private ByteBuffer serverIn; // read side of serverEngine101102/*103* For data transport, this example uses local ByteBuffers. This104* isn't really useful, but the purpose of this example is to show105* SSLEngine concepts, not how to do network transport.106*/107private ByteBuffer cTOs; // "reliable" transport client->server108private ByteBuffer sTOc; // "reliable" transport server->client109110/*111* The following is to set up the keystores.112*/113private static final String pathToStores = "../../../../javax/net/ssl/etc";114private static final String keyStoreFile = "keystore";115private static final String trustStoreFile = "truststore";116private static final char[] passphrase = "passphrase".toCharArray();117118private static final String keyFilename =119System.getProperty("test.src", ".") + "/" + pathToStores +120"/" + keyStoreFile;121private static final String trustFilename =122System.getProperty("test.src", ".") + "/" + pathToStores +123"/" + trustStoreFile;124125/*126* Main entry point for this test.127*/128public static void main(String args[]) throws Exception {129if (debug) {130System.setProperty("javax.net.debug", "all");131}132133SSLEngineFailedALPN test = new SSLEngineFailedALPN();134test.runTest();135136System.out.println("Test Passed.");137}138139/*140* Create an initialized SSLContext to use for these tests.141*/142public SSLEngineFailedALPN() throws Exception {143144KeyStore ks = KeyStore.getInstance("JKS");145KeyStore ts = KeyStore.getInstance("JKS");146147ks.load(new FileInputStream(keyFilename), passphrase);148ts.load(new FileInputStream(trustFilename), passphrase);149150KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");151kmf.init(ks, passphrase);152153TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");154tmf.init(ts);155156SSLContext sslCtx = SSLContext.getInstance("TLS");157158sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);159160sslc = sslCtx;161}162163/*164* Run the test.165*166* Sit in a tight loop, both engines calling wrap/unwrap regardless167* of whether data is available or not. We do this until both engines168* report back they are closed.169*170* The main loop handles all of the I/O phases of the SSLEngine's171* lifetime:172*173* initial handshaking174* application data transfer175* engine closing176*177* One could easily separate these phases into separate178* sections of code.179*/180private void runTest() throws Exception {181boolean dataDone = false;182183createSSLEngines();184createBuffers();185186// results from client's last operation187SSLEngineResult clientResult;188189// results from server's last operation190SSLEngineResult serverResult;191192/*193* Examining the SSLEngineResults could be much more involved,194* and may alter the overall flow of the application.195*196* For example, if we received a BUFFER_OVERFLOW when trying197* to write to the output pipe, we could reallocate a larger198* pipe, but instead we wait for the peer to drain it.199*/200Exception clientException = null;201Exception serverException = null;202203while (!isEngineClosed(clientEngine)204|| !isEngineClosed(serverEngine)) {205206log("================");207208try {209clientResult = clientEngine.wrap(clientOut, cTOs);210log("client wrap: ", clientResult);211} catch (Exception e) {212clientException = e;213System.out.println("Client wrap() threw: " + e.getMessage());214}215logEngineStatus(clientEngine);216runDelegatedTasks(clientEngine);217218log("----");219220try {221serverResult = serverEngine.wrap(serverOut, sTOc);222log("server wrap: ", serverResult);223} catch (Exception e) {224serverException = e;225System.out.println("Server wrap() threw: " + e.getMessage());226}227logEngineStatus(serverEngine);228runDelegatedTasks(serverEngine);229230cTOs.flip();231sTOc.flip();232233log("--------");234235try {236clientResult = clientEngine.unwrap(sTOc, clientIn);237log("client unwrap: ", clientResult);238} catch (Exception e) {239clientException = e;240System.out.println("Client unwrap() threw: " + e.getMessage());241}242logEngineStatus(clientEngine);243runDelegatedTasks(clientEngine);244245log("----");246247try {248serverResult = serverEngine.unwrap(cTOs, serverIn);249log("server unwrap: ", serverResult);250} catch (Exception e) {251serverException = e;252System.out.println("Server unwrap() threw: " + e.getMessage());253}254logEngineStatus(serverEngine);255runDelegatedTasks(serverEngine);256257cTOs.compact();258sTOc.compact();259260/*261* After we've transfered all application data between the client262* and server, we close the clientEngine's outbound stream.263* This generates a close_notify handshake message, which the264* server engine receives and responds by closing itself.265*/266if (!dataDone && (clientOut.limit() == serverIn.position()) &&267(serverOut.limit() == clientIn.position())) {268269/*270* A sanity check to ensure we got what was sent.271*/272checkTransfer(serverOut, clientIn);273checkTransfer(clientOut, serverIn);274275log("\tClosing clientEngine's *OUTBOUND*...");276clientEngine.closeOutbound();277logEngineStatus(clientEngine);278279dataDone = true;280log("\tClosing serverEngine's *OUTBOUND*...");281serverEngine.closeOutbound();282logEngineStatus(serverEngine);283}284}285286log("================");287288if ((clientException != null) &&289(clientException instanceof SSLHandshakeException)) {290log("Client threw proper exception");291clientException.printStackTrace(System.out);292} else {293throw new Exception("Client Exception not seen");294}295296if ((serverException != null) &&297(serverException instanceof SSLHandshakeException)) {298log("Server threw proper exception:");299serverException.printStackTrace(System.out);300} else {301throw new Exception("Server Exception not seen");302}303}304305private static void logEngineStatus(SSLEngine engine) {306log("\tCurrent HS State " + engine.getHandshakeStatus().toString());307log("\tisInboundDone(): " + engine.isInboundDone());308log("\tisOutboundDone(): " + engine.isOutboundDone());309}310311/*312* Using the SSLContext created during object creation,313* create/configure the SSLEngines we'll use for this test.314*/315private void createSSLEngines() throws Exception {316/*317* Configure the serverEngine to act as a server in the SSL/TLS318* handshake. Also, require SSL client authentication.319*/320serverEngine = sslc.createSSLEngine();321serverEngine.setUseClientMode(false);322serverEngine.setNeedClientAuth(true);323324// Get/set parameters if needed325SSLParameters paramsServer = serverEngine.getSSLParameters();326paramsServer.setApplicationProtocols(new String[]{"one"});327serverEngine.setSSLParameters(paramsServer);328329/*330* Similar to above, but using client mode instead.331*/332clientEngine = sslc.createSSLEngine("client", 80);333clientEngine.setUseClientMode(true);334335// Get/set parameters if needed336SSLParameters paramsClient = clientEngine.getSSLParameters();337paramsClient.setApplicationProtocols(new String[]{"two"});338clientEngine.setSSLParameters(paramsClient);339}340341/*342* Create and size the buffers appropriately.343*/344private void createBuffers() {345346/*347* We'll assume the buffer sizes are the same348* between client and server.349*/350SSLSession session = clientEngine.getSession();351int appBufferMax = session.getApplicationBufferSize();352int netBufferMax = session.getPacketBufferSize();353354/*355* We'll make the input buffers a bit bigger than the max needed356* size, so that unwrap()s following a successful data transfer357* won't generate BUFFER_OVERFLOWS.358*359* We'll use a mix of direct and indirect ByteBuffers for360* tutorial purposes only. In reality, only use direct361* ByteBuffers when they give a clear performance enhancement.362*/363clientIn = ByteBuffer.allocate(appBufferMax + 50);364serverIn = ByteBuffer.allocate(appBufferMax + 50);365366cTOs = ByteBuffer.allocateDirect(netBufferMax);367sTOc = ByteBuffer.allocateDirect(netBufferMax);368369clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());370serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());371}372373/*374* If the result indicates that we have outstanding tasks to do,375* go ahead and run them in this thread.376*/377private static void runDelegatedTasks(SSLEngine engine) throws Exception {378379if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {380Runnable runnable;381while ((runnable = engine.getDelegatedTask()) != null) {382log(" running delegated task...");383runnable.run();384}385HandshakeStatus hsStatus = engine.getHandshakeStatus();386if (hsStatus == HandshakeStatus.NEED_TASK) {387throw new Exception(388"handshake shouldn't need additional tasks");389}390logEngineStatus(engine);391}392}393394private static boolean isEngineClosed(SSLEngine engine) {395return (engine.isOutboundDone() && engine.isInboundDone());396}397398/*399* Simple check to make sure everything came across as expected.400*/401private static void checkTransfer(ByteBuffer a, ByteBuffer b)402throws Exception {403a.flip();404b.flip();405406if (!a.equals(b)) {407throw new Exception("Data didn't transfer cleanly");408} else {409log("\tData transferred cleanly");410}411412a.position(a.limit());413b.position(b.limit());414a.limit(a.capacity());415b.limit(b.capacity());416}417418/*419* Logging code420*/421private static boolean resultOnce = true;422423private static void log(String str, SSLEngineResult result) {424if (!logging) {425return;426}427if (resultOnce) {428resultOnce = false;429System.out.println("The format of the SSLEngineResult is: \n" +430"\t\"getStatus() / getHandshakeStatus()\" +\n" +431"\t\"bytesConsumed() / bytesProduced()\"\n");432}433HandshakeStatus hsStatus = result.getHandshakeStatus();434log(str +435result.getStatus() + "/" + hsStatus + ", " +436result.bytesConsumed() + "/" + result.bytesProduced() +437" bytes");438if (hsStatus == HandshakeStatus.FINISHED) {439log("\t...ready for application data");440}441}442443private static void log(String str) {444if (logging) {445System.out.println(str);446}447}448}449450451