Qt server and android ssl client Certificates - java

I Use Qtas server side,and android as client side.
I set in SSLSocketFactory certification
private ConnectionManager(MBoxConfiguration config) {
try {
this.config = config;
try {
trusted.load(in, "password".toCharArray());
} finally {
in.close();
}
SSLSocketFactory sf = new SSLSocketFactory(trusted);
Socket socket;
socket = ssf.createSocket();
socket.connect(new InetSocketAddress(config.ip, config.port));
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = MainActivity.context.getResources().openRawResource(R.raw.truststore);
try {
trusted.load(in, "password".toCharArray());
} finally {
in.close();
}
ssf = new SSLSocketFactory(trusted);
ssf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
} catch (Exception e) {
e.printStackTrace();
}
}
When I want connect to server, in QT is give me that error
Thread Address in peerVerifyError "The peer did not present any certificate"
Thread Address in sslErrors ("The peer did not present any certificate")
Thread Address in error QAbstractSocket::SocketError( 13 )
Thread Address in destroyThreadfirst: QThread(0x12ec9448)
Thread Address in destroyThread: QThread(0x12ec9238)

http://qt-project.org/doc/qt-5.1/qtnetwork/qsslsocket.html
Look at the description of QSslSocket::sslErrors
Try to hook up sslErrors signal and then call the slot ignoreSslErrors() from there to ignore the errors, that should help.

Related

SSLPeerUnverifiedException: peer not authenticated with self signed certificates in netbeans 8.2 on localhost

I have been googling this error for hours and nothing worked so far and tbh I have no idea why...I generate my certificates like this:
client:
keytool -genkey -alias babicaprivate -keystore babica.private -storetype JKS -keyalg rsa -dname "CN=Babica" -storepass babicapwd -keypass babicapwd -validity 365
keytool -export -alias babicaprivate -keystore babica.private -file temp.key -storepass babicapwd
keytool -import -noprompt -alias babicapublic -keystore client.public -file temp.key -storepass public
del temp.key
server:
keytool -genkey -alias serverprivate -keystore server.private -storetype JKS -keyalg rsa -dname "CN=localhost" -storepass serverpwd -keypass serverpwd -validity 365
keytool -export -alias serverprivate -keystore server.private -file temp.key -storepass serverpwd
keytool -import -noprompt -alias serverpublic -keystore server.public -file temp.key -storepass public
del temp.key
this gives me public and private certificates for server and client
then I start the server and client and when I try to sign on the server and try to read the "Common name" from the client on server with
Socket newClientSocket = ss.accept();
((SSLSocket)newClientSocket).startHandshake();
String username = ((SSLSocket) newClientSocket).getSession().getPeerPrincipal().getName();
and it's the username fetching that gives me the error and I have no idea why. Is there something wrong with how I make the certificates?
Here is my full code for server:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.net.ssl.*;
import java.security.*;
public class ChatServer {
protected List<Socket> clients = new ArrayList<Socket>(); // list of clients
private String[][] portUserPair = new String[10][2];
int i = 0;
private String passphrase = "serverpwd";
private int port = 1234;
public static void main(String[] args) throws Exception {
new ChatServer();
}
public ChatServer() throws Exception {
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("client.public"), "public".toCharArray());
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("server.private"), passphrase.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(clientKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(serverKeyStore, passphrase.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
SSLContext.setDefault(sslContext);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), (new SecureRandom()));
SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket ss = (SSLServerSocket) factory.createServerSocket(port);
ss.setNeedClientAuth(false);
ss.setEnabledCipherSuites(new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
// start listening for new connections
System.out.println("[system] listening ...");
try {
while (true) {
Socket newClientSocket = ss.accept(); // wait for a new client connection
((SSLSocket)newClientSocket).startHandshake();
String username = ((SSLSocket) newClientSocket).getSession().getPeerPrincipal().getName();
System.out.println("Established SSL connection with: " + username);
synchronized(this) {
portUserPair[i][0] = Integer.toString(newClientSocket.getPort());
clients.add(newClientSocket); // add client to the list of clients
}
ChatServerConnector conn = new ChatServerConnector(this, newClientSocket); // create a new thread for communication with the new client
conn.start(); // run the new thread
}
} catch (Exception e) {
System.err.println("[error] Accept failed.");
e.printStackTrace(System.err);
System.exit(1);
}
// close socket
System.out.println("[system] closing server socket ...");
try {
ss.close();
} catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
// send a message to all clients connected to the server
public void sendToAllClients(String message) throws Exception {
Iterator<Socket> i = clients.iterator();
while (i.hasNext()) { // iterate through the client list
Socket socket = (Socket) i.next(); // get the socket for communicating with this client
try {
DataOutputStream out = new DataOutputStream(socket.getOutputStream()); // create output stream for sending messages to the client
out.writeUTF(message); // send message to the client
} catch (Exception e) {
System.err.println("[system] could not send message to a client");
e.printStackTrace(System.err);
}
}
}
public void sendToAClient(String message, String userInfo) throws Exception {
Socket userSocket = null;
String userPort = "";
Iterator<Socket> i = clients.iterator();
for (int k = 0; k < portUserPair.length; k++) {
if(portUserPair[k][1].equals(userInfo)) {
userPort = portUserPair[k][0];
break;
}
}
System.out.println(userPort);
while (i.hasNext()) { // iterate through the client list
Socket socket = (Socket) i.next(); // get the socket for communicating with this client
if(Integer.toString(socket.getPort()).equals(userPort)) {
userSocket = socket;
break;
}
}
message = message.substring(userInfo.length()+2);
try {
DataOutputStream out = new DataOutputStream(userSocket.getOutputStream()); // create output stream for sending messages to the client
out.writeUTF(message); // send message to the client
} catch (Exception e) {
System.err.println("[system] could not send message to the client");
e.printStackTrace(System.err);
}
}
public void removeClient(Socket socket) {
synchronized(this) {
clients.remove(socket);
}
}
public void saveUserInfo(String userInfo) {
portUserPair[i][1] = userInfo;
System.out.println(portUserPair[i][0] + " : " + portUserPair[i][1]);
i++;
}
}
class ChatServerConnector extends Thread {
private ChatServer server;
private Socket socket;
public ChatServerConnector(ChatServer server, Socket socket) {
this.server = server;
this.socket = socket;
}
public void run() {
System.out.println("[system] connected with " + this.socket.getInetAddress().getHostName() + ":" + this.socket.getPort());
DataInputStream in;
try {
in = new DataInputStream(this.socket.getInputStream()); // create input stream for listening for incoming messages
} catch (IOException e) {
System.err.println("[system] could not open input stream!");
e.printStackTrace(System.err);
this.server.removeClient(socket);
return;
}
while (true) { // infinite loop in which this thread waits for incoming messages and processes them
String msg_received;
try {
msg_received = in.readUTF(); // read the message from the client
} catch (Exception e) {
System.err.println("[system] there was a problem while reading message client on port " + this.socket.getPort());
e.printStackTrace(System.err);
this.server.removeClient(this.socket);
return;
}
if (msg_received.length() == 0) // invalid message
continue;
String[] msg = msg_received.split(" ");
System.out.println(msg_received);
if (msg[1].equals("system")) {
// try {
// server.saveUserInfo(((SSLSocket) socket).getSession().getPeerPrincipal().getName());
// } catch (SSLPeerUnverifiedException ex) {
// Logger.getLogger(ChatServerConnector.class.getName()).log(Level.SEVERE, null, ex);
// }
continue;
}
System.out.println(msg_received); // print the incoming message in the console
String msg_send = msg_received.toUpperCase();
if (msg[3].charAt(0) == '/') {
String[] privateMsg = msg[3].split(" ");
try {
this.server.sendToAClient(msg_send, privateMsg[0].replace("/", "")); // send message to the client
} catch (Exception e) {
System.err.println("[system] there was a problem while sending the message to the client");
e.printStackTrace(System.err);
continue;
}
continue;
}
try {
this.server.sendToAllClients(msg_send); // send message to all clients
} catch (Exception e) {
System.err.println("[system] there was a problem while sending the message to all clients");
e.printStackTrace(System.err);
continue;
}
}
}
}
and here is my cleint:
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
import javax.net.ssl.*;
import java.security.*;
public class ChatClient extends Thread {
private String userInfo = "";
private String passphrase = "pwd";
private int port = 1234;
public static void main(String[] args) throws Exception {
new ChatClient();
}
public ChatClient() throws Exception {
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("server.public"), "public".toCharArray());
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
Scanner s = new Scanner(System.in);
String username = s.nextLine();
clientKeyStore.load(new FileInputStream(username + ".private"), (username + passphrase).toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(serverKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(clientKeyStore, (username + passphrase).toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
SSLContext.setDefault(sslContext);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
SSLSocketFactory sf = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) sf.createSocket("localhost", port);
socket.setEnabledCipherSuites(new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
socket.startHandshake();
DataInputStream in = null;
DataOutputStream out = null;
// connect to the chat server
try {
System.out.println("[system] connecting to chat server ...");
System.out.println("[system] you are signed in as: " + username);
in = new DataInputStream(socket.getInputStream()); // create input stream for listening for incoming messages
out = new DataOutputStream(socket.getOutputStream()); // create output stream for sending messages
this.sendMessage(username, out, "system");
System.out.println("[system] connected");
System.out.println("[system] to send a private message type \"/<NameOfUser>\" and then type the message");
ChatClientMessageReceiver message_receiver = new ChatClientMessageReceiver(in); // create a separate thread for listening to messages from the chat server
message_receiver.start(); // run the new thread
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
// read from STDIN and send messages to the chat server
BufferedReader std_in = new BufferedReader(new InputStreamReader(System.in));
String userInput;
while ((userInput = std_in.readLine()) != null) { // read a line from the console
this.sendMessage(userInput, out, userInfo); // send the message to the chat server
}
// cleanup
out.close();
in.close();
std_in.close();
socket.close();
}
private void sendMessage(String message, DataOutputStream out, String userInfo) {
message = "[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + userInfo + " : " + message;
try {
out.writeUTF(message); // send the message to the chat server
out.flush(); // ensure the message has been sent
} catch (IOException e) {
System.err.println("[system] could not send message");
e.printStackTrace(System.err);
}
}
}
// wait for messages from the chat server and print the out
class ChatClientMessageReceiver extends Thread {
private DataInputStream in;
public ChatClientMessageReceiver(DataInputStream in) {
this.in = in;
}
public void run() {
try {
String message;
while ((message = this.in.readUTF()) != null) { // read new message
System.out.println(message); // print the message to the console
}
} catch (Exception e) {
System.err.println("[system] could not read message");
e.printStackTrace(System.err);
}
}
}
the whole thing is supposed to be a "chat" that uses SSL to encrypt messages and should get the username from the certificate...so I have everything figured out except the "getting the usename out of the certificate's 'Common name' field"
Help, I'm losing my mind over this! :'(
ss.setNeedClientAuth(false);
The problem is here. You never asked for the client certificate, so it never got sent. Change this to true.

Client/Server JVM_Bind exception

I am trying to establish a SSL connection between java server and python client.
Here is the code:
Server side:
public class s implements Runnable {
List<SSLSocket> socketList= new ArrayList<SSLSocket>();
List<File> FileList= new ArrayList<File>();
List<Certificate> CertificateList = new ArrayList<Certificate>();
public static void main(String[] args) {
s manager = new s();
new Thread(manager).start();
Scanner scanner = new Scanner(System.in);
while(true){
System.out.printf("Send> ");
String message = scanner.nextLine();
if(message.equals("") || message.equals("/n")){
continue;
}else{
manager.send(message);
}
}
}
private static SSLServerSocket getServerSocket(int thePort)
{
SSLServerSocket s=null;
try
{
String key="G:\\mySrvKeystore";
char keyStorePass[]="123456".toCharArray();
char keyPassword[]="123456".toCharArray();
KeyStore ks= KeyStore.getInstance("JKS");
ks.load(new FileInputStream(key),keyStorePass);
KeyManagerFactory kmf= KeyManagerFactory.getInstance("SunX509");
kmf.init(ks,keyPassword);
SSLContext sslContext= SSLContext.getInstance("SSLv3");
sslContext.init(kmf.getKeyManagers(),null,null);
SSLServerSocketFactory factory=sslContext.getServerSocketFactory();
s=(SSLServerSocket)factory.createServerSocket(thePort);
}catch(Exception e)
{
System.out.println(e);
}
return(s);
}
public void run() {
try {
while (true) {
SSLServerSocket sslserversocket = getServerSocket(**9991**);
SSLSocket client = (SSLSocket)sslserversocket.accept();
socketList.add(client);
new Thread(new SSocket(client,socketList,FileList)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Client side:
class timer(threading.Thread):
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.ssl_sock = ssl.wrap_socket(self.sock, ssl_version=ssl.PROTOCOL_SSLv3)
self.ssl_sock.connect(('localhost',9990))
self.isrun = True
threading.Thread.__init__(self);
def run(self):
while self.isrun:
revice = self.ssl_sock.recv(1024);
print ("recv> " + revice);
self.sock.close();
self.ssl_sock.close();
def send(self,str):
self.ssl_sock.send(str + "\n")
def close(self):
self.isrun=False
if __name__=='__main__':
main()
I got:
I did not use reserve port and my OS is windows-7. And I run the server first then the client.
I don't understand why I cannot run multiple instance of the program?
Is it because I am using the same port?
But it was ok before when I just used socket instead of SSLsocket.
THanks for any help
You cannot have multiple server processes listening to the same port. How would the OS know which one gets the connection?
The usual way to handle multiple clients is to spawn a thread AFTER you have accepted a connection. You pass the connection to the thread and the main thread loops, continuing to listen and accept new connections.
This is all very basic TCP/IP and has nothing to do with SSL.

Android Https Connection with self signed certificate : hostName not verified

Hi I am testing Android connecion with certificate.
I have created a default ssl server on my ubuntu desktop. Enabled ssl and created the default self-signed certificate. I have then connected to https://localhost with firefox, added certificate to exceptions and then I used Firefox to save cerificate as .pem file.
I added certificate.pem to my android projetc in res/raw
I have gotten this code from android developer website to connect via https using my certificate (I don't want to trust everything I just want to verify if certicate is correct using the certificate in raw folder).
So when I connect I get:
java.lang.RuntimeException: java.io.IOException: Hostname '192.168.1.111' was not verified
Here is the class I use to verify the certificate
public class VerifyKey extends AsyncTask<Void, Void, Void>{
public static final String CERTIFICATE_TYPE_X_509 = "X.509";
public static final String CERTIFICATE_ALIAS = "user_desktop";
public static final String SERVER_URL = "https://192.168.1.111";
#Override
protected Void doInBackground(Void... params) {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = null;
InputStream certificateInputStream = getApplicationContext().getResources().openRawResource(R.raw.user_desktop);
Certificate certificate = null;
try {
cf = CertificateFactory.getInstance(CERTIFICATE_TYPE_X_509);
certificate = cf.generateCertificate(certificateInputStream);
Log.d(TAG, "Certificate : " + certificate.toString());
Log.d(TAG, "Certificate public key : " + certificate.getPublicKey());
} catch (CertificateException e) {
throw new RuntimeException(e);
} finally {
if (certificateInputStream != null) {
try {
certificateInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance(keyStoreType);
if (keyStore != null) {
keyStore.load(null, null);
keyStore.setCertificateEntry(CERTIFICATE_ALIAS, certificate);
} else {
throw new RuntimeException("KeyStore is null");
}
} catch (KeyStoreException e) {
throw new RuntimeException(e);
} catch (CertificateException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = null;
try {
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
if (tmf != null) {
tmf.init(keyStore);
} else {
throw new RuntimeException("TrustManagerFactory is null");
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers();
sslContext.init(null, trustManagers, null);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (KeyManagementException e) {
throw new RuntimeException(e);
}
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = null;
HttpsURLConnection httpsURLConnection =
null;
InputStream in = null;
try {
url = new URL(SERVER_URL);
Log.d(TAG, "URL : "+url.toString());
httpsURLConnection = (HttpsURLConnection)url.openConnection();
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
Log.d(TAG, "Socket factory : "+socketFactory.toString());
httpsURLConnection.setSSLSocketFactory(socketFactory);
in = httpsURLConnection.getInputStream(); //IOException exception gets triggered here
Toast.makeText(getApplicationContext(), in.toString(), Toast.LENGTH_SHORT).show();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (SSLHandshakeException e){
throw new RuntimeException(e);
} catch(UnknownHostException e){
throw new RuntimeException(e);
} catch (ConnectException e1){
throw new RuntimeException(e1);
} catch (IOException e) {
throw new RuntimeException(e);
}
return null;
}
}
I have gotten this code from http://developer.android.com/training/articles/security-ssl.html#SelfSigned
I get this error on Samsung Galaxy s4 with Android 4.3
I don't have a lot of experience with HTTPS so here what I would like to achieve is povide certificate with the app which will allow to verify the server certificate.
Please if someone can suggest what I can modify in the code.
I also have a doubt because my server is a .local server but I connect using ip and the objective is to be able to connect using both ip a hostname, will that be problem when veryfying the hostname?
Thanks a lot in advance
EDIT: I have added code to get the hostname:
InetAddress addr = InetAddress.getByName(SERVER_URL);
String hostName = addr.getHostName();
I have tried using the hostname instead of ip but still I get the same exception:
Caused by: java.io.IOException: Hostname '<user.hostname.com>' was not verified
at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
I have managed to solve the problem, it was actually a problem with the certificate:
sudo a2enmod ssl
sudo rm -rf /etc/apache2/ssl
sudo mkdir /etc/apache2/ssl
sudo openssl req -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.key
copy /etc/apache2/ssl/apache.pem somewhere else, change permissions of it to 777 (???)
and then add new apache.pem to res/raw folder of the app
then in common name field I have set the FQDN of my server such as host.name.com, I then updated the cerificate and key settings in /etc/apache2/sites-available/default-ssl
All this thanks to site https://library.linode.com/web-servers/apache/ssl-guides/ubuntu-10.04-lucid

Java multiple SSL client to one server

I'm currently working on a tiny individual project for this semester with Android. What I'm going to do is making lots of connections to my https server with my Android phone so the server goes down. I know absolutely nothing about programming because I'm studying networking not computer language. But I somehow collected from here and there piece by piece and made a code like below. I think it's using a socket connection.
import java.net.*;
import java.io.*;
import java.security.*;
import javax.net.ssl.*;
public class HTTPSClient {
public static void main(String[] args) {
System.out.println("Usage: java HTTPSClient host");
int port = 443; // default https port
String host = "192.168.0.8";
TrustManager[] trustAll = new javax.net.ssl.TrustManager[]{
new javax.net.ssl.X509TrustManager(){
public java.security.cert.X509Certificate[] getAcceptedIssuers(){
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs,String authType){}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs,String authType){}
}
};
try {
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
sc.init(null, trustAll, new java.security.SecureRandom());
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
SSLSocketFactory factory = (SSLSocketFactory) sc.getSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
Writer out = new OutputStreamWriter(socket.getOutputStream());
out.write("GET / HTTP/1.0\\r\\n");
out.write("\\r\\n");
out.flush();
// read response
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
int c;
while ((c = in.read()) != -1) {
System.out.write(c);
}
// out.close();
// in.close();
// socket.close();
} catch (Exception e) {
System.err.println(e);
}
}
}
I enabled https on my macbook and I can see the port 443 listening. When I execute the code above I can see one established connection through 'netstat -an | grep 443' until I stop it. My question is this: if I want to make multiple connection with this code, what should I add on? Is it possible with this code? My idea is that if I can see heaps of established connections to 443 port on my macbook, I will not be able to connect https:://localhost with a browser because the machine is down. I don't know if it's correct but I hope. Because the semester is almost over and I anyway have to make something to report.
I'm not sure if that code will be the same when I make the code for Android phone but I just want to see something happening first. I'm really desperate, please help me. Thank you very much.
From what I can understand, you are trying to have multiple clients(phones) connect to your server.
Your server looks solid. You should be able to modify it to handle multiple clients easily.
Generally you need a handler of some sort to process incoming client connections. You will need a loop to wait for new connections, and then a thread to handle each connection independently. Each instance of a socket can only handle one connection. A socket factory allows you to bind more than once instance of a socket to the server. I have two classes to handle multiple connections. My first class is the server itself and the second is a a thread to handle each client.
If you are not familiar with threading, you should check into it.
This is the server class:
public class ServerThread extends Thread
{
private Vector<ClientHandlerThread> connectedClients = new Vector<ClientHandlerThread>(20, 5);
public void run()
{
SSLServerSocket sslDataTraffic = null;
SSLServerSocket sslFileTraffic = null;
SSLServerSocketFactory sslFac = null;
try
{
System.out.print("Validating SSL certificate... ");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(certificateDir), password);
System.out.println("DONE.");
System.out.print("Creating trust engine........ ");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
System.out.println("DONE.");
System.out.print("Creating key engine.......... ");
KeyManagerFactory kmf = KeyManagerFactory.getInstance((KeyManagerFactory.getDefaultAlgorithm()));
kmf.init(keyStore, password);
System.out.println("DONE.");
System.out.print("Creating SSL context......... ");
System.setProperty("https.protocols", "SSL");
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
sslFac = ctx.getServerSocketFactory();
System.out.println("DONE.");
}
catch (Exception e) {}
try
{
System.out.print("Creating data socket......... ");
sslDataTraffic = (SSLServerSocket) sslFac.createServerSocket(dataPort);
System.out.println("DONE. Est. on:" + dataPort);
}
catch (IOException e)
{
System.out.println("FAILED.");
System.out.println(e.toString() + " ::: " + e.getCause());
System.exit(-1);
}
try
{
System.out.print("Creating file socket......... ");
sslFileTraffic = (SSLServerSocket) sslFac.createServerSocket(filePort);
System.out.println("DONE. Est. on:" + filePort);
}
catch (IOException e)
{
System.out.println("FAILED.");
System.out.println(e.toString() + " ::: " + e.getCause());
System.exit(-1);
}
while (running)
{
SSLSocket sslDataTrafficSocketInstance = (SSLSocket) sslDataTraffic.accept();
SSLSocket sslFileTrafficSocketInstance = (SSLSocket) sslFileTraffic.accept();
ClientHandlerThread c = new ClientHandlerThread(sslDataTrafficSocketInstance, sslFileTrafficSocketInstance);
c.start();
connectedClients.add(c);
}
}
Notice the while loop at the end of the class. It will wait until a client connects (which invokes the accept() method). An independent thread is created to handle that client (phone).
The client thread is as follows:
public class ClientHandlerThread extends Thread
{
private boolean running = true;
private SSLSocket dataSocket;
private SSLSocket fileSocket;
private PrintWriter writer;
private BufferedReader reader;
private InputStream inputStream;
private OutputStream outputStream;
public ClientHandlerThread(
SSLSocket dataSocket,
SSLSocket fileSocket)
{
this.dataSocket = dataSocket;
this.fileSocket = fileSocket;
try
{
this.reader = new BufferedReader(new InputStreamReader(this.dataSocket.getInputStream()));
this.writer = new PrintWriter(this.dataSocket.getOutputStream());
this.inputStream = fileSocket.getInputStream();
this.outputStream = fileSocket.getOutputStream();
}
catch (IOException e)
{
e.printStackTrace();
}
this.ip = this.dataSocket.getInetAddress().getHostAddress();
}
public void run()
{
try
{
writer.println("SERVER_HANDSHAKE_INIT");
writer.flush();
String fromClient;
while (running && (fromClient = reader.readLine()) != null)
{
if (fromClient.equals("CLIENT_HANDSHAKE_INIT"))
System.out.println("Client Connected: " + getIP());
}
}
catch (IOException e)
{
e.getCause();
}
}
public String getIP()
{
return ip;
}
public boolean isRunning()
{
return running;
}
public void setRunning(boolean running)
{
this.running = running;
}
}
You now have the ability to iterate through each client thread held within the Vector containing all clients. This will allow you to handle multiple clients and interact with each of them independently. This includes reading input/output streams.
These classes are stripped down versions of the ones I use for a simple remote management system I developed over the summer. You should be able to modify them as necessary to meet your needs. You could add a parameter to the client thread constructor to keep track of naming for example.
I hope this explained how to handle multiple incoming connections to a server.
Feel free to DM or email me for additional info.
Cheers
You could change your code to open connections in a loop:
int numConnections = 100;
for (int i=0; i<numConnections; i++) {
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
Writer out = new OutputStreamWriter(socket.getOutputStream());
out.write("GET / HTTP/1.0\\r\\n");
out.write("\\r\\n");
out.flush();
// read response
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
int c;
while ((c = in.read()) != -1) {
System.out.write(c);
}
// out.close();
// in.close();
// socket.close();
}
I highly suggest retaining the socket objects in an array or collection variable and closing the I/O streams and socket when you are done, but this will also be done when main() exits - just know this is generally bad practice in programming if you were to want to reuse this code in a situation where the whole program didn't exit after the block of code that opens connection(s).

Java SSL sockets not working

I am using TCP/IP sockets to create a client and server applicaton. Originally I was using regular sockets but now I have decided to use SSL for my connection. I have created a keystore and have tried running my application but it has yet to be successful.
Here is my code for the server
public class ArFileServer {
public static void main(String[] args)
{
boolean listening = true;
ServerSocketFactory serversocketfactory;
ServerSocket serverSocket;
try
{
//serverSocket = new ServerSocket(4445);
serversocketfactory = SSLServerSocketFactory.getDefault();
serverSocket = serversocketfactory.createServerSocket(4445);
String keystore = System.getProperty("javax.net.ssl.trustStore");
System.out.println(keystore);
// infinite loop to continually listen for connection requests made by clients
while (listening)
{
new ClientConnection(serverSocket.accept()).start();
if (serverSocket != null)
{
System.out.println("Connection to client established");
}
}
serverSocket.close();
}
catch (IOException e)
{
System.out.println("Error could not create socket connection to port, check that port is not busy");
}
}
}
and here is the client code:
public class ClientSocket
{
SocketFactory socketfactory = null;
Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;
// establish a connection to All Care's server application through socket 4444 (adjust localhost to reflect the IP address that the server
// is being run from)
public ClientSocket()
{
try
{
//clientSocket = new Socket("localhost", 4445);
//SocketFactory socketfactory = SSLSocketFactory.getDefault();
clientSocket = socketfactory.createSocket("192.168.1.8", 4445);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String truststore = System.getProperty("javax.net.ssl.trustStore");
System.out.println(truststore);
}
catch (IOException e)
{
System.out.println("Could not connect to All Care Server Application : " + e.getMessage());
}
}
}
I am also using these runtime arguments:
-Djavax.net.ssl.keyStore=C:\Users\Chris\Documents\NetBeansProjects\ArFile\keystore.jks -Djavax.net.ssl.keyStorePassword=password
When I try to print out the truststore it always returns null, what am I doing wrong?
When I try to print out the truststore it always returns null
Because you never set it. All you are doing is printing out the value of a system property. If you didn't set it, it is null.
what am I doing wrong?
Nothing yet, except printing out meaningless information. But much of your code doesn't make sense:
if (serverSocket != null)
{
System.out.println("Connection to client established");
}
serverSocket being non-null (a) is inevitable at this point, and (b) doesn't have anything do with the client socket being established, which is inevitable at this point.
catch (IOException e)
{
System.out.println("Error could not create socket connection to port, check that port is not busy");
}
An IOException at this point could mean many things, but the one thing it doesn't mean is 'cannot create socket connection to port'. It is the client that does the connecting: the server accepts connections. When you catch an exception, always print its message, don't just make up your own.
You need to define both trustStore and keyStore in runtime arguments:
-Djavax.net.ssl.keyStore=xxx.ks
-Djavax.net.ssl.keyStorePassword=yyy
-Djavax.net.ssl.trustStore=xxx.ks
-Djavax.net.ssl.trustStorePassword=yyy
Both can be same file.
trustStore contains public keys of others.
keyStore contains own keys and certificates.

Categories

Resources