/*
* 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.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* SSLSocketImplTest
*/
public class SSLSocketFunctionalTest extends TestCase {
/**
* The cipher suites used for functionality testing.
*/
private String[] cipher_suites = {
"RSA_WITH_RC4_128_MD5",
"RSA_WITH_DES_CBC_SHA",
"DH_anon_EXPORT_WITH_DES40_CBC_SHA"
};
// turn on/off the debug logging
private boolean doLog = false;
/**
* Sets up the test case.
*/
public void setUp() throws Exception {
if (doLog) {
System.out.println("========================");
System.out.println("====== Running the test: " + getName());
System.out.println("========================");
}
}
public void testContextInitialized2() throws Throwable {
doTestSelfInteraction(JSSETestData.getContext());
}
public void doTestInteraction(SSLContext context, SSLContext ctx_other)
throws Throwable {
SSLContext ctx1, ctx2;
ctx1 = context;
ctx2 = ctx_other;
int k=1;
SSLServerSocket ssocket = (SSLServerSocket) ctx1
.getServerSocketFactory().createServerSocket(0);
ssocket.setUseClientMode(false);
ssocket.setEnabledCipherSuites(
((k & 1) > 0)
? new String[] {"TLS_"+cipher_suites[0]}
: new String[] {"SSL_"+cipher_suites[0]});
SSLSocket csocket = (SSLSocket) ctx2
.getSocketFactory().createSocket("localhost",
ssocket.getLocalPort());
csocket.setEnabledProtocols(new String[] {"TLSv1"});
csocket.setUseClientMode(true);
csocket.setEnabledCipherSuites(
(((k & 2) >> 1) > 0)
? new String[] {"TLS_"+cipher_suites[0]}
: new String[] {"SSL_"+cipher_suites[0]});
doTest(ssocket, csocket);
}
public void _doTestInteraction(SSLContext context, SSLContext ctx_other)
throws Throwable {
for (int i=0; i<cipher_suites.length; i++) {
if (doLog) {
System.out.println("======== Checking the work on cipher: "
+ cipher_suites[i]);
}
SSLContext ctx1, ctx2;
// k: 00, 01, 10, 11;
// where 1 means implementation under the test,
// 0 - another implementation to interract with
for (int k=0; k<4; k++) {
if (doLog) {
System.out.println("======== "+(k & 1)+" "+((k & 2) >> 1));
}
ctx1 = ((k & 1) > 0) ? context : ctx_other;
ctx2 = (((k & 2) >> 1) > 0) ? context : ctx_other;
SSLServerSocket ssocket = (SSLServerSocket) ctx1
.getServerSocketFactory().createServerSocket(0);
ssocket.setUseClientMode(false);
ssocket.setEnabledCipherSuites(
((k & 1) > 0)
? new String[] {"TLS_"+cipher_suites[i]}
: new String[] {"SSL_"+cipher_suites[i]});
SSLSocket csocket = (SSLSocket) ctx2
.getSocketFactory().createSocket("localhost",
ssocket.getLocalPort());
csocket.setEnabledProtocols(new String[] {"TLSv1"});
csocket.setUseClientMode(true);
csocket.setEnabledCipherSuites(
(((k & 2) >> 1) > 0)
? new String[] {"TLS_"+cipher_suites[i]}
: new String[] {"SSL_"+cipher_suites[i]});
doTest(ssocket, csocket);
}
}
}
/**
* Tests the interaction with other implementation.
*/
public void doTestSelfInteraction(SSLContext context)
throws Throwable {
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("======= " + cipher_suites[i]);
}
SSLServerSocket ssocket = (SSLServerSocket) context
.getServerSocketFactory().createServerSocket(0);
ssocket.setUseClientMode(false);
ssocket.setEnabledProtocols(new String[] {protocols[j]});
ssocket.setEnabledCipherSuites(
new String[] {"TLS_"+cipher_suites[i]});
SSLSocket csocket = (SSLSocket) context
.getSocketFactory().createSocket("localhost",
ssocket.getLocalPort());
csocket.setEnabledProtocols(new String[] {protocols[j]});
csocket.setUseClientMode(true);
csocket.setEnabledCipherSuites(
new String[] {"TLS_"+cipher_suites[i]});
doTest(ssocket, csocket);
}
}
}
private static class HandshakeListener
implements HandshakeCompletedListener {
boolean compleated = false;
public void handshakeCompleted(HandshakeCompletedEvent event) {
compleated = true;
}
}
/**
* Performs SSL connection between the sockets
* @return
*/
public void doTest(SSLServerSocket ssocket, SSLSocket csocket)
throws Throwable {
final String server_message = "Hello from SSL Server Socket!";
final String client_message = "Hello from SSL Socket!";
Thread server = null;
Thread client = null;
final Throwable[] throwed = new Throwable[1];
try {
final SSLServerSocket ss = ssocket;
final SSLSocket s = csocket;
server = new Thread() {
public void run() {
InputStream is = null;
OutputStream os = null;
SSLSocket s = null;
try {
s = (SSLSocket) ss.accept();
if (doLog) {
System.out.println("Socket accepted: " + s);
}
is = s.getInputStream();
os = s.getOutputStream();
// send the message to the client
os.write(server_message.getBytes());
// read the response
byte[] buff = new byte[client_message.length()];
int len = is.read(buff);
if (doLog) {
System.out.println("Received message of length "
+ len + ": '" + new String(buff, 0, len)+"'");
}
assertTrue("Read message does not equal to expected",
Arrays.equals(client_message.getBytes(), buff));
os.write(-1);
assertEquals("Read data differs from expected",
255, is.read());
if (doLog) {
System.out.println("Server is closed: "
+s.isClosed());
}
assertEquals("Returned value should be -1",
// initiate an exchange of closure alerts
-1, is.read());
if (doLog) {
System.out.println("Server is closed: "
+s.isClosed());
}
assertEquals("Returned value should be -1",
// initiate an exchange of closure alerts
-1, is.read());
} catch (Throwable e) {
synchronized (throwed) {
if (doLog) {
e.printStackTrace();
}
if (throwed[0] == null) {
throwed[0] = e;
}
}
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException ex) {}
try {
if (os != null) {
os.close();
}
} catch (IOException ex) {}
try {
if (s != null) {
s.close();
}
} catch (IOException ex) {}
}
}
};
client = new Thread() {
public void run() {
InputStream is = null;
OutputStream os = null;
try {
assertTrue("Client was not connected", s.isConnected());
if (doLog) {
System.out.println("Client connected");
}
is = s.getInputStream();
os = s.getOutputStream();
s.startHandshake();
if (doLog) {
System.out.println("Client: HS was done");
}
// read the message from the server
byte[] buff = new byte[server_message.length()];
int len = is.read(buff);
if (doLog) {
System.out.println("Received message of length "
+ len + ": '" + new String(buff, 0, len)+"'");
}
assertTrue("Read message does not equal to expected",
Arrays.equals(server_message.getBytes(), buff));
// send the response
buff = (" "+client_message+" ").getBytes();
os.write(buff, 1, buff.length-2);
assertEquals("Read data differs from expected",
255, is.read());
os.write(-1);
if (doLog) {
System.out.println("\n======== Closing ========");
}
if (doLog) {
System.out.println("Client is closed: "
+s.isClosed());
}
s.close();
if (doLog) {
System.out.println("Client is closed: "
+s.isClosed());
}
} catch (Throwable e) {
synchronized (throwed) {
if (doLog) {
e.printStackTrace();
}
if (throwed[0] == null) {
throwed[0] = e;
}
}
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException ex) {}
try {
if (os != null) {
os.close();
}
} catch (IOException ex) {}
try {
if (s != null) {
s.close();
}
} catch (IOException ex) {}
}
}
};
server.start();
client.start();
while (server.isAlive() || client.isAlive()) {
if (throwed[0] != null) {
throw throwed[0];
}
try {
Thread.sleep(500);
} catch (Exception e) { }
}
} finally {
if (server != null) {
server.stop();
}
if (client != null) {
client.stop();
}
}
if (throwed[0] != null) {
throw throwed[0];
}
}
public static Test suite() {
return new TestSuite(SSLSocketFunctionalTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
}