/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.harmony.xnet.provider.jsse; import java.nio.ByteBuffer; import java.util.Arrays; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * SSLEngine implementation test. */ public class SSLEngineImplTest extends TestCase { /** * The cipher suites used for functionality testing. */ private static final String[] cipher_suites = { "RSA_WITH_RC4_128_MD5", "RSA_WITH_DES_CBC_SHA", "DH_anon_EXPORT_WITH_DES40_CBC_SHA" }; /** * Test logging switch. */ private static boolean doLog = false; /** * Sets up the test case. */ @Override public void setUp() throws Exception { if (doLog) { System.out.println(""); System.out.println("========================"); System.out.println("====== Running the test: " + getName()); System.out.println("========================"); } } /** * Tests the interaction between the engines. */ public void testSelfInteraction() throws Exception { String[] protocols = {"SSLv3", "TLSv1"}; for (int i=0; i 0); // tune buffer to be read buffer.flip(); try { // should rethrow the SSLException "internal error" print(client.unwrap(buffer, app_data_buffer)); fail("Expected exception was not thrown."); } catch (Exception ex) { if (doLog) { System.out.println("Client rethrew received alert: " + ex.getMessage()); } // NOT_HANDSHAKING.. assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, client.getHandshakeStatus()); client.closeOutbound(); // NEED_WRAP.. should it be so? it contradicts to the TLS spec: // "Upon transmission or receipt of an fatal alert message, both // parties immediately close the connection. Servers and clients // are required to forget any session-identifiers, keys, and // secrets associated with a failed connection." // So in this case we expect NOT_HANDSHAKING assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, client.getHandshakeStatus()); assertTrue("Outbound should be closed.", client.isOutboundDone()); assertTrue("Inbound should be closed.", client.isInboundDone()); } } } /** * closeInbound() method testing. * Tests error processing */ public void testErrorProcessing() throws Exception { SSLEngine client = getEngine(); SSLEngine server = getEngine(); initEngines(client, server); int packetBufferSize = client.getSession().getPacketBufferSize(); int applicationBufferSize = server.getSession().getApplicationBufferSize(); ByteBuffer buffer = ByteBuffer.allocate(packetBufferSize); ByteBuffer app_data_buffer = ByteBuffer.allocate(applicationBufferSize); client.setUseClientMode(true); server.setUseClientMode(false); doHandshake(client, server); if (doLog) { System.out.println("\nError processing test:"); } try { print(server.unwrap(ByteBuffer.allocate(40), app_data_buffer)); fail("Expected exception was not thrown."); } catch (Exception e) { if (doLog) { System.out.println("\nServer threw exception: " +e.getMessage()); } assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_WRAP, server.getHandshakeStatus()); SSLEngineResult result = null; assertFalse("Outbound should not be closed.", server.isOutboundDone()); assertTrue("Inbound should be closed.", server.isInboundDone()); if (doLog) { System.out.println( "\nServer tries to unwrap the data after error"); } print(result = server.unwrap(ByteBuffer.allocate(40), app_data_buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_WRAP, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertEquals( "The length of the produced data differs from expected", 0, result.bytesProduced()); if (doLog) { System.out.println("\nServer wraps the fatal alert"); } print(result = server.wrap(ByteBuffer.allocate(0), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertTrue( "The length of the produced data differs from expected", result.bytesProduced() > 0); assertTrue("Outbound should be closed.", server.isOutboundDone()); assertTrue("Inbound should be closed.", server.isInboundDone()); buffer.flip(); try { if (doLog) { System.out.println("\nClient unwraps the fatal alert"); } print(client.unwrap(buffer, app_data_buffer)); fail("Expected exception was not thrown."); } catch (Exception ex) { if (doLog) { System.out.println("\nClient rethrew the exception: " + ex.getMessage()); } // NOT_HANDSHAKING.. assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, client.getHandshakeStatus()); client.closeOutbound(); // NEED_WRAP.. should it be so? it contradicts to the TLS spec: // "Upon transmission or receipt of an fatal alert message, both // parties immediately close the connection. Servers and clients // are required to forget any session-identifiers, keys, and // secrets associated with a failed connection." // So in this case we expect NOT_HANDSHAKING assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, client.getHandshakeStatus()); assertTrue("Outbound should be closed.", client.isOutboundDone()); assertTrue("Inbound should be closed.", client.isInboundDone()); } } } // -------------------------------------------------------------------- // ------------------------ Staff methods ----------------------------- // -------------------------------------------------------------------- /* * Performs the handshake over the specified engines */ private void doHandshake(SSLEngine client, SSLEngine server) throws Exception { if (doLog) { System.out.println("\n--- doHandshake:"); System.out.println("Server: "+server.getSession().getClass()); System.out.println("Client: "+client.getSession().getClass()); } client.beginHandshake(); server.beginHandshake(); doHandshakeImpl(client, server); } /* * Performs the handshake over the specified engines. * Note that method passes app data between the engines during * the handshake process. */ private void doHandshakeImpl(SSLEngine client, SSLEngine server) throws Exception { if (doLog) { System.out.println("\n--- doHandshakeImpl:"); System.out.println("Client's hsh status: " + client.getHandshakeStatus()); System.out.println("Client's session: "+client.getSession()); System.out.println("Server's hsh status: " + server.getHandshakeStatus()); System.out.println("Server's session: "+server.getSession()); } int packetBufferSize = client.getSession().getPacketBufferSize(); int applicationBufferSize = server.getSession().getApplicationBufferSize(); // buffer will contain handshake messages ByteBuffer clients_buffer = ByteBuffer.allocate(packetBufferSize+1000); ByteBuffer servers_buffer = ByteBuffer.allocate(packetBufferSize+1000); // buffers will contain application data messages ByteBuffer app_data = ByteBuffer.allocate(packetBufferSize); ByteBuffer app_data_plain = ByteBuffer.allocate(applicationBufferSize); SSLEngine[] engines = new SSLEngine[] {client, server}; ByteBuffer[] buffers = new ByteBuffer[] {clients_buffer, servers_buffer}; // choose which peer will start handshake negotiation // (initial handshake is initiated by client, but rehandshake // can be initiated by any peer) int step = (client.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) ? 0 : 1; SSLEngine current_engine = engines[step]; ByteBuffer buffer; SSLEngineResult result = null; SSLEngineResult.HandshakeStatus status; while ((client.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) || (server.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) { if (doLog) { System.out.print("\n" + ((current_engine == client) ? "CLIENT " : "SERVER ")); } status = current_engine.getHandshakeStatus(); if (status == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { // so another peer produced // the handshaking data which has to be unwrapped if (doLog) { System.out.print("(NOT_HANDSHAKING) "); } status = SSLEngineResult.HandshakeStatus.NEED_UNWRAP; } if (status == SSLEngineResult.HandshakeStatus.NEED_WRAP) { if (doLog) { System.out.println("NEED_WRAP"); } // will wrap handshake data into its special buffer buffer = buffers[step]; if (buffer.remaining() == 0) { // handshake data was fully read by another peer, // so we need clear the buffer before reusing it buffer.clear(); } // wrap the next handshake message print(result = current_engine.wrap(app_data, buffer)); // if there are no any messages to send, switch the engine if (current_engine.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NEED_WRAP) { // switch the current engine step ^= 1; current_engine = engines[step]; // and prepare the buffer for reading buffer.flip(); } } else if (status == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { if (doLog) { System.out.println("NEED_UNWRAP"); } // If there are no unread handshake messages produced by the // current engine, try to wrap the application data and unwrap // it by another engine. It will test app data flow during // the rehandshake. if (!buffers[step].hasRemaining()) { if (doLog) { System.out.println( "\nTry to WRAP the application data"); } print(result = current_engine.wrap( ByteBuffer.wrap(new byte[] {0}), app_data)); // The output in app_data will be produced only if it // is rehandshaking stage // (i.e. initial handshake has been done) if (result.bytesProduced() > 0) { // if the app data message has been produced, // unwrap it by another peer if (doLog) { System.out.print("\n" + ((current_engine != client) ? "CLIENT " : "SERVER ")); System.out.println( "UNWRAPs app data sent during handshake"); } app_data.flip(); print(result = engines[(step+1)%2].unwrap( app_data, app_data_plain)); app_data.clear(); app_data_plain.clear(); } } buffer = buffers[step^1]; // check if there is handshake data to be unwrapped if (buffer.remaining() == 0) { if (doLog) { System.out.println( "There is no handshake data to be unwrapped."); } // switch the current engine step ^= 1; current_engine = engines[step]; if ((current_engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) && (buffers[step^1].remaining() == 0)) { System.out.println( "Both engines are in NEED_UNWRAP state"); fail("Both engines are in NEED_UNWRAP state"); } continue; } print(result = current_engine.unwrap(buffer, app_data)); if (current_engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { if (doLog) { System.out.println("NEED_TASK"); } current_engine.getDelegatedTask().run(); if (doLog) { System.out.println("status after the task: " +current_engine.getHandshakeStatus()); } } } else { fail("Unexpected HandshakeStatus: "+status); } assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); } } /* * Performs the session renegotiation process when one * of the peers is not allowed to create the session. */ private void doNoRenegotiationTest(SSLEngine allowed, SSLEngine not_allowed, boolean is_initial) throws Exception { if (doLog) { System.out.println( "\n--- doNoRenegotiationTest: is_initial: "+is_initial); } not_allowed.setEnableSessionCreation(false); not_allowed.getSession().invalidate(); int packetBufferSize = allowed.getSession().getPacketBufferSize(); int applicationBufferSize = not_allowed.getSession().getApplicationBufferSize(); // buffer will contain handshake messages ByteBuffer buffer = ByteBuffer.allocate(packetBufferSize+1000); // buffers will contain application data messages ByteBuffer app_data = ByteBuffer.allocate(packetBufferSize); ByteBuffer app_data_plain = ByteBuffer.allocate(applicationBufferSize); SSLEngineResult result = null; allowed.beginHandshake(); //not_allowed.beginHandshake(); if (doLog) { System.out.println( "\nAllowed peer wraps the initial session negotiation message"); } // wrap the initial session negotiation message while (allowed.getHandshakeStatus().equals( SSLEngineResult.HandshakeStatus.NEED_WRAP)) { print(result = allowed.wrap(app_data_plain, buffer)); assertTrue("Engine did not produce any data", result.bytesProduced() > 0); } // prepare the buffer for reading buffer.flip(); if (doLog) { System.out.println("\nNot allowed unwraps the message"); } try { // unwrap the message. expecting whether SSLException or NEED_WRAP print(result = not_allowed.unwrap(buffer, app_data_plain)); } catch (SSLException e) { if (is_initial) { return; // ok, exception was thrown } else { fail("Unexpected SSLException was thrown "+e); } } // if it is not an initial handshake phase it is posible // SSLException to be thrown. try { while (!not_allowed.getHandshakeStatus().equals( SSLEngineResult.HandshakeStatus.NEED_WRAP)) { assertTrue("Engine did not consume any data", result.bytesConsumed() > 0); if (not_allowed.getHandshakeStatus().equals( SSLEngineResult.HandshakeStatus.NEED_TASK)) { not_allowed.getDelegatedTask().run(); if (doLog) { System.out.println("Status after the task: " + not_allowed.getHandshakeStatus()); } continue; } else if (not_allowed.getHandshakeStatus().equals( SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) { print(result = not_allowed.unwrap(buffer, app_data_plain)); } else { fail("Unexpected status of operation: " + not_allowed.getHandshakeStatus()); } } // prepare for writting buffer.clear(); if (doLog) { System.out.println( "\nWrapping the message. Expecting no_renegotiation alert"); } // wrapping the message. expecting no_renegotiation alert print(result = not_allowed.wrap(app_data_plain, buffer)); } catch (SSLException e) { if (!is_initial) { fail("Unexpected SSLException was thrown."+e.getMessage()); } if (doLog) { System.out.println("Throwed exception during the unwrapping " + "of handshake initiation message:"); e.printStackTrace(); System.out.println("Handshake Status: " + not_allowed.getHandshakeStatus()); } if (not_allowed.getHandshakeStatus().equals( SSLEngineResult.HandshakeStatus.NEED_WRAP)) { // needs to wrap fatal alert message if (doLog) { System.out.println( "\nnot_allowed wraps fatal alert message"); } // prepare for writting buffer.clear(); print(result = not_allowed.wrap(app_data_plain, buffer)); } } // check whether alert message has been sent assertTrue("Engine did not produce any data", result.bytesProduced() > 0); // check whether not_allowed engine stoped handshake operation assertEquals("Unexpected status of operation: not_allowed " + "to session creation peer did not stop its handshake process", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, not_allowed.getHandshakeStatus()); // prepare for reading buffer.flip(); try { print(result = allowed.unwrap(buffer, app_data_plain)); assertTrue("Engine did not consume any data", result.bytesConsumed() > 0); assertEquals("Responce from the peer not allowed to create " + "the session did not cause the stopping of " + "the session negotiation process", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); } catch (SSLException e) { if (!is_initial) { fail("Unexpected SSLException was thrown."+e.getMessage()); } if (doLog) { System.out.println("Throwed exception during the unwrapping " + "of responce from allowed peer:"); e.printStackTrace(); System.out.println("Handshake Status: " + not_allowed.getHandshakeStatus()); } } } /* * Tests the data exchange process between two engines */ private void doDataExchange(SSLEngine client, SSLEngine server) throws Exception { if (doLog) { System.out.println("\n--- doDataExchange:"); } ByteBuffer co = ByteBuffer.allocate( client.getSession().getPacketBufferSize()); ByteBuffer si = ByteBuffer.allocate( server.getSession().getPacketBufferSize()); SSLEngineResult result; String data_2b_sent = "data to be sent"; ByteBuffer data = ByteBuffer.wrap(data_2b_sent.getBytes()); if (doLog) { System.out.println("\nTry to wrap the data into small buffer"); } print(result = client.wrap(data, ByteBuffer.allocate(35))); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); if (doLog) { System.out.println("\nWrapping the data of length " + data.remaining()); } print(result = client.wrap(data, co)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); // tune the buffer to read from it co.limit(co.position()); co.rewind(); if (doLog) { System.out.println("\nTry to unwrap the data into small buffer"); } print(result = server.unwrap(co, ByteBuffer.allocate(0))); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); if (doLog) { System.out.println("\nUnwrapping the data into buffer"); } print(result = server.unwrap(co, si)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); assertEquals( "The length of the received data differs from expected", "data to be sent".length(), result.bytesProduced()); // take the data from the buffer byte[] resulting_data = new byte[result.bytesProduced()]; si.rewind(); si.get(resulting_data); si.clear(); assertTrue(Arrays.equals(data_2b_sent.getBytes(), resulting_data)); co.clear(); for (int i=1; i<10; i++) { byte[] buff = new byte[i]; data = ByteBuffer.wrap(buff); if (doLog) { System.out.println("\nWrap the data"); } print(result = client.wrap(data, co)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); if (doLog) { System.out.println("\nUnwrap the data"); } co.rewind(); print(result = server.unwrap(co, si)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); assertEquals( "The length of the received data differs from expected", i, result.bytesProduced()); resulting_data = new byte[i]; si.rewind(); si.get(resulting_data); si.clear(); assertTrue(Arrays.equals(buff, resulting_data)); co.clear(); si.clear(); } } /* * Performs the closure process over the two communicationg engines. * The handshake process should be performed before the call of this * method. */ private void doClose(SSLEngine client, SSLEngine server) throws Exception { if (doLog) { System.out.println("\n--- doClose: "); } ByteBuffer buffer = ByteBuffer.allocate( // +100 because we put the data into the buffer multiple times server.getSession().getPacketBufferSize()+100); ByteBuffer app_data_buffer = ByteBuffer.allocate( client.getSession().getApplicationBufferSize()); SSLEngineResult result; // first: send 0 just for fun if (doLog) { System.out.println("\nServer sends pending outboud data:"); } print(result = server.wrap(ByteBuffer.wrap(new byte[] {0}), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); // second: initiate a close if (doLog) { System.out.println("\nServer initiates a closure:"); } server.closeOutbound(); // should do nothing: server.closeOutbound(); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_WRAP, server.getHandshakeStatus()); // will cause SSLException because closure alert was not received yet: // server.closeInbound(); // wrap closure alert (previosly sent 0 should not be lost) print(result = server.wrap(ByteBuffer.allocate(0), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus()); if (doLog) { System.out.println("\nServer sends pending outboud data again:"); } // will do nothing because closure alert has been sent // and outbound has been closed print(result = server.wrap(ByteBuffer.wrap(new byte[] {0}), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertEquals( "The length of the produced data differs from expected", 0, result.bytesProduced()); // prepare the buffer for reading buffer.flip(); if (doLog) { System.out.println( "\nClient receives pending servers' outbound data"); } print(result = client.unwrap(buffer, app_data_buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.OK, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertEquals( "The length of the produced data differs from expected", 1, result.bytesProduced()); app_data_buffer.clear(); if (doLog) { System.out.println("\nClient receives close notify"); } print(result = client.unwrap(buffer, app_data_buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_WRAP, result.getHandshakeStatus()); assertTrue( "The length of the consumed data differs from expected", result.bytesConsumed() > 0); assertEquals( "The length of the received data differs from expected", 0, result.bytesProduced()); // prepare the buffer for writing app_data_buffer.clear(); // it's needless, but should work (don't cause exceptions): client.closeInbound(); client.closeOutbound(); if (doLog) { System.out.println("\nClient tries to read data again"); } // CLOSED, 0 consumed, 0 produced print(result = client.unwrap(buffer, app_data_buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NEED_WRAP, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertEquals( "The length of the received data differs from expected", 0, result.bytesProduced()); // prepare the buffer for writing buffer.clear(); if (doLog) { System.out.println("\nClient sends responding close notify"); } print(result = client.wrap(ByteBuffer.wrap(new byte[] {0}), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertTrue( "The length of the produced data differs from expected", result.bytesProduced() > 0); if (doLog) { System.out.println( "\nClient tries to send data after closure alert"); } // this data will not be sent (should do nothing - 0 cons, 0 prod) print(result = client.wrap(ByteBuffer.wrap(new byte[] {0}), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertEquals( "The length of the produced data differs from expected", 0, result.bytesProduced()); // prepare the buffers for reading app_data_buffer.clear(); buffer.flip(); if (doLog) { System.out.println("\nServer receives close notify"); } print(result = server.unwrap(buffer, app_data_buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertTrue( "The length of the consumed data differs from expected", result.bytesConsumed() > 0); assertEquals( "The length of the produced data differs from expected", 0, result.bytesProduced()); if (doLog) { System.out.println("\nServer tries to read after closure"); } // will be ignored print(result = server.unwrap(buffer, app_data_buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertEquals( "The length of the produced data differs from expected", 0, result.bytesProduced()); // it's needless, but should work: client.closeInbound(); // will be ignored if (doLog) { System.out.println("\nServer tries to write after closure"); } buffer.clear(); print(result = server.wrap(ByteBuffer.allocate(0), buffer)); assertEquals("Unexpected status of operation:", SSLEngineResult.Status.CLOSED, result.getStatus()); assertEquals("Unexpected status of operation:", SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, result.getHandshakeStatus()); assertEquals( "The length of the consumed data differs from expected", 0, result.bytesConsumed()); assertEquals( "The length of the produced data differs from expected", 0, result.bytesProduced()); } private static void print(SSLEngineResult result) { if (doLog) { System.out.println("result:\n"+result); } } /** * Returns the engine to be tested. */ private SSLEngine getEngine() throws Exception { return JSSETestData.getContext().createSSLEngine("localhost", 2345); } /** * Initializes the engines. */ private void initEngines(SSLEngine client, SSLEngine server) { String prefix = "TLS_"; client.setEnabledProtocols(new String[] {"TLSv1"}); server.setEnabledProtocols(new String[] {"TLSv1"}); client.setEnabledCipherSuites( new String[] {prefix+cipher_suites[0]}); server.setEnabledCipherSuites( new String[] {prefix+cipher_suites[0]}); client.setUseClientMode(true); server.setUseClientMode(false); } public static Test suite() { return new TestSuite(SSLEngineImplTest.class); } }