| /* |
| * 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 < cipher_suites.length; i++) { |
| for (int j = 0; j < 2; j++) { |
| if (doLog) { |
| System.out.println("\n===== Interact over suite: " |
| + cipher_suites[i]); |
| } |
| SSLEngine client = getEngine(); |
| SSLEngine server = getEngine(); |
| initEngines(client, server); |
| |
| doHandshake(client, server); |
| doDataExchange(client, server); |
| doClose(client, server); |
| } |
| } |
| } |
| |
| /** |
| * Tests the session negotiation process. |
| */ |
| public void testHandshake() throws Exception { |
| SSLEngine client = getEngine(); |
| SSLEngine server = getEngine(); |
| |
| initEngines(client, server); |
| |
| // checks the impossibility of initial handshake |
| // with the server not allowed to session creation |
| doNoRenegotiationTest(client, server, true); |
| |
| client = getEngine(); |
| server = getEngine(); |
| initEngines(client, server); |
| |
| client.setUseClientMode(true); |
| server.setUseClientMode(false); |
| |
| // do initial handshake |
| doHandshake(client, server); |
| |
| // client initiates rehandshake |
| client.beginHandshake(); |
| doHandshakeImpl(client, server); |
| |
| // server initiates rehandshake |
| server.beginHandshake(); |
| doHandshakeImpl(client, server); |
| |
| // client initiates rehandshake while server invalidates |
| // used session |
| server.getSession().invalidate(); |
| client.beginHandshake(); |
| doHandshakeImpl(client, server); |
| |
| // server initiates rehandshake while client invalidates |
| // used session |
| client.getSession().invalidate(); |
| server.beginHandshake(); |
| doHandshakeImpl(client, server); |
| |
| client.getSession().invalidate(); |
| server.getSession().invalidate(); |
| doHandshake(client, server); |
| |
| doNoRenegotiationTest(client, server, false); |
| |
| doNoRenegotiationTest(server, client, false); |
| |
| doClose(client, server); |
| } |
| |
| /** |
| * setNeedClientAuth(boolean need) method testing. |
| * getNeedClientAuth() method testing. |
| */ |
| public void testSetGetNeedClientAuth() throws Exception { |
| SSLEngine engine = getEngine(); |
| |
| engine.setWantClientAuth(true); |
| engine.setNeedClientAuth(false); |
| assertFalse("Result differs from expected", |
| engine.getNeedClientAuth()); |
| assertFalse("Socket did not reset its want client auth state", |
| engine.getWantClientAuth()); |
| engine.setWantClientAuth(true); |
| engine.setNeedClientAuth(true); |
| assertTrue("Result differs from expected", |
| engine.getNeedClientAuth()); |
| assertFalse("Socket did not reset its want client auth state", |
| engine.getWantClientAuth()); |
| } |
| |
| /** |
| * setWantClientAuth(boolean want) method testing. |
| * getWantClientAuth() method testing. |
| */ |
| public void testSetGetWantClientAuth() throws Exception { |
| SSLEngine engine = getEngine(); |
| |
| engine.setNeedClientAuth(true); |
| engine.setWantClientAuth(false); |
| assertFalse("Result differs from expected", |
| engine.getWantClientAuth()); |
| assertFalse("Socket did not reset its want client auth state", |
| engine.getNeedClientAuth()); |
| engine.setNeedClientAuth(true); |
| engine.setWantClientAuth(true); |
| assertTrue("Result differs from expected", |
| engine.getWantClientAuth()); |
| assertFalse("Socket did not reset its want client auth state", |
| engine.getNeedClientAuth()); |
| } |
| |
| /** |
| * getSupportedCipherSuites() method testing. |
| */ |
| public void testGetSupportedCipherSuites() throws Exception { |
| SSLEngine engine = getEngine(); |
| String[] supported = engine.getSupportedCipherSuites(); |
| assertNotNull(supported); |
| supported[0] = "NOT_SUPPORTED_CIPHER_SUITE"; |
| supported = engine.getEnabledCipherSuites(); |
| for (int i = 0; i < supported.length; i++) { |
| if ("NOT_SUPPORTED_CIPHER_SUITE".equals(supported[i])) { |
| fail("Modification of the returned result " |
| + "causes the modification of the internal state"); |
| } |
| } |
| } |
| |
| /** |
| * getEnabledCipherSuites() method testing. |
| */ |
| public void testGetEnabledCipherSuites() throws Exception { |
| SSLEngine engine = getEngine(); |
| String[] enabled = engine.getEnabledCipherSuites(); |
| assertNotNull(enabled); |
| String[] supported = engine.getSupportedCipherSuites(); |
| for (int i = 0; i < enabled.length; i++) { |
| found: |
| { |
| for (int j = 0; j < supported.length; j++) { |
| if (enabled[i].equals(supported[j])) { |
| break found; |
| } |
| } |
| fail("Enabled suite does not belong to the set " |
| + "of supported cipher suites: " + enabled[i]); |
| } |
| } |
| engine.setEnabledCipherSuites(supported); |
| for (int i = 0; i < supported.length; i++) { |
| enabled = new String[supported.length - i]; |
| System.arraycopy(supported, 0, |
| enabled, 0, supported.length - i); |
| engine.setEnabledCipherSuites(enabled); |
| String[] result = engine.getEnabledCipherSuites(); |
| if (result.length != enabled.length) { |
| fail("Returned result differs from expected."); |
| } |
| for (int k = 0; k < result.length; k++) { |
| found: |
| { |
| for (int n = 0; n < enabled.length; n++) { |
| if (result[k].equals(enabled[n])) { |
| break found; |
| } |
| } |
| if (result.length != enabled.length) { |
| fail("Returned result does not correspond " |
| + "to expected."); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * setEnabledCipherSuites(String[] suites) method testing. |
| */ |
| public void testSetEnabledCipherSuites() throws Exception { |
| SSLEngine engine = getEngine(); |
| String[] enabled = engine.getEnabledCipherSuites(); |
| assertNotNull(enabled); |
| String[] supported = engine.getSupportedCipherSuites(); |
| for (int i = 0; i < enabled.length; i++) { |
| found: |
| { |
| for (int j = 0; j < supported.length; j++) { |
| if (enabled[i].equals(supported[j])) { |
| break found; |
| } |
| } |
| fail("Enabled suite does not belong to the set " |
| + "of supported cipher suites: " + enabled[i]); |
| } |
| } |
| engine.setEnabledCipherSuites(supported); |
| engine.setEnabledCipherSuites(enabled); |
| engine.setEnabledCipherSuites(supported); |
| String[] more_than_supported = new String[supported.length + 1]; |
| for (int i = 0; i < supported.length + 1; i++) { |
| more_than_supported[i] |
| = "NOT_SUPPORTED_CIPHER_SUITE"; |
| System.arraycopy(supported, 0, |
| more_than_supported, 0, i); |
| System.arraycopy(supported, i, |
| more_than_supported, i + 1, supported.length - i); |
| try { |
| engine.setEnabledCipherSuites(more_than_supported); |
| fail("Expected IllegalArgumentException was not thrown"); |
| } catch (IllegalArgumentException e) { |
| } |
| } |
| enabled = engine.getEnabledCipherSuites(); |
| enabled[0] = "NOT_SUPPORTED_CIPHER_SUITE"; |
| enabled = engine.getEnabledCipherSuites(); |
| for (int i = 0; i < enabled.length; i++) { |
| if ("NOT_SUPPORTED_CIPHER_SUITE".equals(enabled[i])) { |
| fail("Modification of the returned result " |
| + "causes the modification of the internal state"); |
| } |
| } |
| } |
| |
| /** |
| * getSupportedProtocols() method testing. |
| */ |
| public void testGetSupportedProtocols() throws Exception { |
| SSLEngine engine = getEngine(); |
| String[] supported = engine.getSupportedProtocols(); |
| assertNotNull(supported); |
| assertFalse(supported.length == 0); |
| supported[0] = "NOT_SUPPORTED_PROTOCOL"; |
| supported = engine.getSupportedProtocols(); |
| for (int i = 0; i < supported.length; i++) { |
| if ("NOT_SUPPORTED_PROTOCOL".equals(supported[i])) { |
| fail("Modification of the returned result " |
| + "causes the modification of the internal state"); |
| } |
| } |
| } |
| |
| /** |
| * getEnabledProtocols() method testing. |
| */ |
| public void testGetEnabledProtocols() throws Exception { |
| SSLEngine engine = getEngine(); |
| String[] enabled = engine.getEnabledProtocols(); |
| assertNotNull(enabled); |
| String[] supported = engine.getSupportedProtocols(); |
| for (int i = 0; i < enabled.length; i++) { |
| found: |
| { |
| for (int j = 0; j < supported.length; j++) { |
| if (enabled[i].equals(supported[j])) { |
| break found; |
| } |
| } |
| fail("Enabled protocol does not belong to the set " |
| + "of supported protocols: " + enabled[i]); |
| } |
| } |
| engine.setEnabledProtocols(supported); |
| for (int i = 0; i < supported.length; i++) { |
| enabled = new String[supported.length - i]; |
| System.arraycopy(supported, i, |
| enabled, 0, supported.length - i); |
| engine.setEnabledProtocols(enabled); |
| String[] result = engine.getEnabledProtocols(); |
| if (result.length != enabled.length) { |
| fail("Returned result differs from expected."); |
| } |
| for (int k = 0; k < result.length; k++) { |
| found: |
| { |
| for (int n = 0; n < enabled.length; n++) { |
| if (result[k].equals(enabled[n])) { |
| break found; |
| } |
| } |
| if (result.length != enabled.length) { |
| fail("Returned result does not correspond " |
| + "to expected."); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * setUseClientMode(boolean mode) method testing. |
| * getUseClientMode() method testing. |
| */ |
| public void testSetGetUseClientMode() throws Exception { |
| SSLEngine engine = getEngine(); |
| |
| engine.setUseClientMode(false); |
| assertFalse("Result differs from expected", |
| engine.getUseClientMode()); |
| engine.setUseClientMode(true); |
| assertTrue("Result differs from expected", |
| engine.getUseClientMode()); |
| |
| engine.beginHandshake(); |
| try { |
| engine.setUseClientMode(false); |
| fail("Expected IllegalArgumentException was not thrown"); |
| } catch (IllegalArgumentException e) { |
| } |
| |
| engine.wrap(ByteBuffer.allocate(0), ByteBuffer.allocate( |
| engine.getSession().getPacketBufferSize())); |
| try { |
| engine.setUseClientMode(false); |
| fail("Expected IllegalArgumentException was not thrown"); |
| } catch (IllegalArgumentException e) { |
| } |
| } |
| |
| /** |
| * setEnableSessionCreation(boolean flag) method testing. |
| * getEnableSessionCreation() method testing. |
| */ |
| public void testSetGetEnableSessionCreation() throws Exception { |
| SSLEngine engine = getEngine(); |
| |
| engine.setEnableSessionCreation(false); |
| assertFalse("Result differs from expected", |
| engine.getEnableSessionCreation()); |
| engine.setEnableSessionCreation(true); |
| assertTrue("Result differs from expected", |
| engine.getEnableSessionCreation()); |
| } |
| |
| /** |
| * getSession() method testing. |
| */ |
| public void testGetSession() throws Exception { |
| SSLEngine engine = getEngine(); |
| |
| SSLSession session = engine.getSession(); |
| if ((session == null) |
| || (!session.getCipherSuite() |
| .endsWith("_NULL_WITH_NULL_NULL"))) { |
| fail("Returned session is null " |
| + "or not TLS_NULL_WITH_NULL_NULL"); |
| } |
| } |
| |
| /** |
| * beginHandshake() method testing |
| */ |
| public void testBeginHandshake() throws Exception { |
| SSLEngine engine = getEngine(); |
| assertEquals("Incorrect initial handshake status", |
| engine.getHandshakeStatus(), |
| SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING); |
| try { |
| engine.beginHandshake(); |
| fail("Expected IllegalStateException was not thrown"); |
| } catch (IllegalStateException e) { |
| } |
| |
| engine = getEngine(); |
| engine.setUseClientMode(false); |
| engine.beginHandshake(); |
| assertEquals("Incorrect initial handshake status", |
| engine.getHandshakeStatus(), |
| SSLEngineResult.HandshakeStatus.NEED_UNWRAP); |
| |
| engine = getEngine(); |
| engine.setUseClientMode(true); |
| engine.beginHandshake(); |
| assertEquals("Incorrect initial handshake status", |
| engine.getHandshakeStatus(), |
| SSLEngineResult.HandshakeStatus.NEED_WRAP); |
| } |
| |
| /** |
| * closeOutbound() method testing. |
| */ |
| public void testCloseOutbound() throws Exception { |
| SSLEngine engine = getEngine(); |
| assertFalse(engine.isOutboundDone()); |
| engine.closeOutbound(); |
| SSLEngineResult result = engine.wrap(ByteBuffer.allocate(0), |
| ByteBuffer.allocate(20000)); |
| assertEquals("Incorrect status", result.getStatus(), |
| SSLEngineResult.Status.CLOSED); |
| assertEquals("Incorrect status", result.getHandshakeStatus(), |
| SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING); |
| try { |
| // should throw SSLException "engine already closed" |
| engine.beginHandshake(); |
| fail("Expected exception was not thrown."); |
| } catch (SSLException e) { |
| } |
| assertTrue(engine.isOutboundDone()); |
| } |
| |
| /** |
| * closeInbound() method testing. |
| */ |
| public void testCloseInbound() throws Exception { |
| SSLEngine engine = getEngine(); |
| assertFalse(engine.isInboundDone()); |
| engine.closeInbound(); |
| SSLEngineResult result = engine.wrap(ByteBuffer.allocate(0), |
| ByteBuffer.allocate(20000)); |
| assertEquals("Incorrect status", result.getStatus(), |
| SSLEngineResult.Status.CLOSED); |
| assertEquals("Incorrect status", result.getHandshakeStatus(), |
| SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING); |
| try { |
| // should throw SSLException "engine already closed" |
| engine.beginHandshake(); |
| fail("Expected exception was not thrown."); |
| } catch (SSLException e) { |
| } |
| assertTrue(engine.isInboundDone()); |
| } |
| |
| /** |
| * closeInbound() method testing. |
| * Tests error processing in the case of unexpected closeInbound. |
| */ |
| public void testCloseInbound2() 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 { |
| // should cause SSLException, prepare fatal alert "internal error", |
| // and set HandshakeStatus to NEED_WRAP |
| // (to send alert to another side) |
| server.closeInbound(); |
| fail("Expected exception was not thrown."); |
| } catch (Exception e) { |
| if (doLog) { |
| System.out.println("Server threw exception: " |
| + e.getMessage()); |
| } |
| // e.printStackTrace(); |
| // should do nothing |
| server.closeInbound(); |
| assertEquals("Unexpected status:", |
| SSLEngineResult.HandshakeStatus.NEED_WRAP, |
| server.getHandshakeStatus()); |
| |
| if (doLog) { |
| System.out.println("Wrapping of the alert message"); |
| } |
| SSLEngineResult result = null; |
| 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); |
| // 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); |
| } |
| |
| } |