Java Client/Server SSL Socket Chat - java

Ok pals, so I have created a java chat using TCP client/server socket.
I create the server, and then i create clients that connect to the server so that they can communicate between each other through the server!
The code: Server:
public ServerChat() throws Exception{
ServerSocket soc=new ServerSocket(5217);
while(true)
{
Socket CSoc=soc.accept();
//and then the code for handling the messages, we don't need that
}
}
And the client:
Server soc=new Socket("127.0.0.1",5217);
Thread t=new Thread(this);
t.start();
//i Have ommited many parts of the code, but you know, i focus on the connection part of the problem!`
So now, I want to use SSL protection(so i can see the changes in wireshark).
I used OpenSSL(it is required for my assingment) to create a root CA and device certificates.I put the files on the src folder on netbeans, and copied the code to two new classes, SSLServer and SSLClient, and experimented a bit on the SSL part! So:
public SSLServer() throws Exception{
SSLContext sslContext=????//supposed to add the files somehow here?
SSLServerSocketFactory factory=(SSLServerSocketFactory)slContext.getServerSocketFactory();
SSLServerSocket sslserversocket=(SSLServerSocket) factory.createServerSocket(1234);
while(true)
{
SSLSocket sslsocket=(SSLSocket)sslserversocket.accept();
}
}
Same thing for the client. So I am a bit stuck on the SSLContext part! I read many threads here but still..
Is the part below SSLContext correct? And how do I use the certificates in SSLContext?
EDIT: Maybe this will work? :
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("keystoreFile"), "keystorePassword".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(ks, "keystorePassword".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(ks);
SSLContext sc = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers();
sc.init(kmf.getKeyManagers(), trustManagers, null);
SSLServerSocketFactory ssf = sc.getServerSocketFactory();
SSLServerSocket s = (SSLServerSocket) ssf.createServerSocket(serverport);
SSLSocket c = (SSLSocket) s.accept();

anyway, i found some links that helped me!
if anyone is interested,
importing an existing x509 certificate and private key in Java keystore to use in ssl
http://www.agentbob.info/agentbob/79-AB.html

Related

SSL Socket Connection Error

I am using JAVA 8. I am trying to connect a Socket Server using client certificates and certificate tree.
I have followings provided by client:
Client CERT (PEM)
Private Key (PEM)
CA Tree (PEM) - with 4 Certificates
I have created keystore.jks using following steps:
Combining client cert and CA tree in a single pem file using cat
Crested PKCS12 file from combined file encrypted using private key(OpenSSL Command)
Generated JKS keystore file using keytool
I have created trustore.jks using following steps:
Split CA Tree (4 certificates) into 4 different files
Generated trustore file using keytool by importing each file one by one
My Sample code is as following :
package com.tutorial.exception.customize;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.util.Scanner;
/**
* Created by SomnathG on 12/1/2016.
*/
public class Client {
public Client() {
System.setProperty("javax.net.ssl.keyStore", {keystore Location});
System.setProperty("javax.net.ssl.keyStorePassword", {password});
System.setProperty("javax.net.ssl.trustStore", {trustore location});
System.setProperty("javax.net.ssl.trustStorePassword", {password});
System.setProperty("javax.net.debug", "all");
System.setProperty( "sun.security.ssl.allowUnsafeRenegotiation", "true" );
}
public void connectHost(){
SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = null;
try {
sslSocket = (SSLSocket) sslSocketFactory.createSocket(host, port);
sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
sslSocket.startHandshake();
InputStream inputStream = sslSocket.getInputStream();
OutputStream outputStream = sslSocket.getOutputStream();
System.out.println("Sending request to Socket Server");
outputStream.write("Hello".getBytes());
outputStream.write("exit".getBytes());
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
int bytesRead = 0;
String messageString = "";
DataInputStream in = new DataInputStream(sslSocket.getInputStream());
while(!end)
{
bytesRead = in.read(messageByte);
messageString += new String(messageByte, 0, bytesRead);
if (messageString.length() == 100)
{
end = true;
}
}
System.out.println("MESSAGE: " + messageString);
// byte[] read = (byte[]) ois.readObject();
//String s2 = new String(read);
//System.out.println("" + s2);
//System.out.println("Message: " + message);
//close resources
//System.out.println(receive(inputStream));
}catch (IOException e) {
e.printStackTrace();
System.out.println("=====");
System.out.println(e.getMessage());
System.out.println("=====");
CertPathValidatorException ce = new CertPathValidatorException(e);
System.out.println("******");
System.out.println(ce.getIndex());
System.out.println(ce.getReason());
System.out.println("******");
//e.printStackTrace();
}
}
public static void main(String[] args){
new Client().connectHost();
}
}
I am getting following exception after executing the code:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: basic constraints check failed: this is not a CA certificate
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at com.tutorial.exception.customize.Client.connectHost(Client.java:33)
at com.tutorial.exception.customize.Client.main(Client.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
After analyzing the log I have found "clientHello" and "serverHello" messages but after that application is throwing above mentioned exception.
What am I doing wrong? Please advice.
Thanks,
Somnath Guha
I have figured out the issue after analyzing the debug lo.
"BasicConstraints" was missing from the server V3 certificates and thus java was failing to recognize the certificate as a valid certificate. Once that constraint has been added then the client was able to handshake with the server and able to communicate with server.
BasicConstraints:[
CA:true
PathLen:2147483647
]

How to get server certificate in java

I am working on a client program(in android) which needs to communicate with a jboss server via SSL. Currently I have followed the instructions from http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html to get the self-signed certificate and connect to the server. I am wondering if this can be done from java since whenever server certificate changes , I have to manually get the certificate and compile it into the code itself. I have also noticed that google chrome in android can do this. Any idea how to achieve this.
Thanks.
I am using this test code to get server certificate without success.
public class TestCert {
public static void main(String args[]) throws Exception {
SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(<ip>, <port>);
socket.startHandshake();
SSLSession session = socket.getSession();
java.security.cert.Certificate[] servercerts = session.getPeerCertificates();
List mylist = new ArrayList();
for (int i = 0; i < servercerts.length; i++) {
mylist.add(servercerts[i]);
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertPath cp = cf.generateCertPath(mylist);
FileOutputStream f = new FileOutputStream("/tmp/CertPath.dat");
ObjectOutputStream b = new ObjectOutputStream(f);
b.writeObject(cp);
}
}

Setting axis.SecureSocketFactory in standalone JRE vs Tomcat

I have a need to replace Axis's (1.4) default SecureSocketFactory with my own implementation. I've done this successfully running from a standalone JRE (1.6), and everything's tested just fine. But when I deploy to Tomcat 5.5 - where this application will eventually reside - as far as I can tell, Axis is still using the JSSESecureSocketFactory. I've tried both:
System.setProperty("org.apache.axis.components.net.SecureSocketFactory", "my.CustomSecureSocketFactory");
and
AxisProperties.setProperty("axis.socketSecureFactory", "my.CustomSecureSocketFactory");
as well as setting the JVM property for Tomcat:
-Dorg.apache.axis.components.net.SecureSocketFactory=my.CustomSecureSocketFactory
The JREs, libraries, key/trust stores, and everything else I can think of are identical. I've even run my standalone test on the server, using Tomcat's JRE and options, and still it works fine.
I'm out of ideas how how to troubleshoot this. Does anyone have any idea of where to look, or an alternate approach to telling Axis to use a specific SecureSocketFactory?
Relevant code snippets:
public class CustomKeyManager extends X509ExtendedKeyManager {
private final X509ExtendedKeyManager base;
public CustomKeyManager(X509ExtendedKeyManager base) {
this.base = base;
}
/* Lots of methods omitted */
static SSLContext SSL_CONTEXT;
static void updateSSL(String keyStoreFile, String keyStorePassword){
System.setProperty("org.apache.axis.components.net.SecureSocketFactory", "com.spanlink.cfg.crypto.HostNameSecureSocketFactory");
AxisProperties.setProperty("axis.socketSecureFactory", "com.spanlink.cfg.crypto.HostNameSecureSocketFactory");
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword.toCharArray());
KeyManager[] oldManagers = kmf.getKeyManagers();
KeyManager[] newManagers = new KeyManager[oldManagers.length];
for (int i = 0; i < oldManagers.length; i++) {
if (oldManagers[i] instanceof X509ExtendedKeyManager) {
newManagers[i] = new CustomKeyManager((X509ExtendedKeyManager) oldManagers[i]);
}else{
newManagers[i] = oldManagers[i];
}
}
SSL_CONTEXT = SSLContext.getInstance("SSL");
SSL_CONTEXT.init(newManagers, null, null);
}
}
public class CustomSecureSocketFactory extends JSSESocketFactory {
public CustomSecureSocketFactory(Hashtable table) {
super(table);
super.sslFactory = CustomKeyManager.SSL_CONTEXT.getSocketFactory();
}
}
Ended up figuring it out. On class load, Axis's SocketFactoryFactory resets the Axis property axis.socketSecureFactory to the default. From a JRE, the class loader loaded SocketFactoryFactory before my code ran; from Tomcat, it wasn't loaded until after my code ran, overwriting my custom settings.
I just added a Class.forName() call before setting axis.socketSecureFactory, and everything worked.

SSL socket connection between PHP client and Java server

I'm attempting to setup an SSL connection between a PHP client and a Java server. I don't know a whole lot about SSL and I'm getting very confused with this.
The connection doesn't need to be trusted or verified, it just has to encrypt the data to make it safe for transfer.
The PHP client is able to connect (acknowledges a connection) to the Java server, but upon the handshake between the two, I reveive the following error in Java:
javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHandshakeException: no cipher suites in common
at sun.security.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1458)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:92)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at com.test.ConnectionHandler.getRequest(ConnectionHandler.java:23)
at com.test.Interaction.run(Interaction.java:35)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.net.ssl.SSLHandshakeException: no cipher suites in common
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1868)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:266)
at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:892)
at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:620)
at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:167)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:998)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1294)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:685)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:111)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
at java.io.BufferedWriter.flush(BufferedWriter.java:254)
at java.io.PrintWriter.newLine(PrintWriter.java:482)
at java.io.PrintWriter.println(PrintWriter.java:629)
at java.io.PrintWriter.println(PrintWriter.java:740)
at com.test.ConnectionHandler.println(ConnectionHandler.java:28)
at com.test.Interaction.run(Interaction.java:29)
... 1 more
and these errors in PHP:
Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages:
error:14077410:SSL routines:func(119):reason(1040) in /var/www/html/inc/node.class.php on line 48
Warning: fsockopen(): Failed to enable crypto in /var/www/html/inc/node.class.php on line 48
Warning: fsockopen(): unable to connect to ssl://127.0.0.1:30627 (Unknown error) in /var/www/html/inc/node.class.php on line 48
This is my code in Java which handles the socket setup:
SSLServerSocketFactory socketfactory;
SSLServerSocket ssock;
SSLContext sslContext = SSLContext.getInstance( "SSL" );
KeyStore ks = KeyStore.getInstance("JKS");
InputStream ksIs = ClassLoader.class.getResourceAsStream("resources/keystore.jks");
try {
ks.load(ksIs, "password".toCharArray());
} catch (CertificateException e) {
e.printStackTrace();
} finally {
if (ksIs != null) {
ksIs.close();
}
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, "password".toCharArray());
sslContext.init( kmf.getKeyManagers(), null, null );
socketfactory = sslContext.getServerSocketFactory();
socketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ssock = (SSLServerSocket) socketfactory.createServerSocket(myPort);
for(String item : ssock.getEnabledCipherSuites()) {
System.out.println(item);
}
while(true) {
SSLSocket sock = (SSLSocket) ssock.accept();
new Interaction(sock);
}
This is my PHP code which handles the connection to the Java server:
(Starting at line 48)
$this->stream = fsockopen("ssl://127.0.0.1", 30627, $errno, $errstr);
if(!$this->stream) {
return array(
'errornum' => $errno,
'errorstr' => $errstr,
);
} else {
return true;
}
Can someone help explain what I'm doing wrong or provide a solution?
--Edit
I've tried using a Java client to connect to see where the problem lies. But I still receive the same error and this is shown on the Java Client:
javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHands
hakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.jav
a:1293)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkWrite(SSLSocketImpl.j
ava:1305)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.ja
va:43)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
at java.io.BufferedWriter.flush(BufferedWriter.java:236)
at Main.main(Main.java:55)
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_
failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.ja
va:1720)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.j
ava:954)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SS
LSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketIm
pl.java:753)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:
75)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at Main$Output.run(Main.java:77)
at java.lang.Thread.run(Thread.java:662)
I figured out that the problem was with loading the keystore. The way I was retrieving it as a resource wasn't working.
I got the keystore to load correctly and everything then worked fine.

Write certificate chain to a PEM file

I am having a certificate chain where it may contain single certificate or certificate along with intermediate CA's certificate. Now I want to write this into a PEM format file. Is it possible to achieve with existing Java libraries without any third party libraries? Below is my code for certificate chain,
final Collection<? extends Certificate> c =
(Collection<? extends Certificate>) certFactory.generateCertificates(
new ByteArrayInputStream(certificateString.getBytes()));
final Certificate[] certs = (Certificate[]) c.toArray(new Certificate[] {});
How can I write this certs into a PEM file?
try this:
BASE64Encoder encoder = new BASE64Encoder();
out.println(X509Factory.BEGIN_CERT);
encoder.encodeBuffer(cert.getEncoded(), out);
out.println(X509Factory.END_CERT);
or try this
import javax.xml.bind.DatatypeConverter;
x509cert.encode();
try {
System.out.println("---BEGIN CERTIFICATE---");
System.out.println(DatatypeConverter.printBase64Binary(x509cert.getEncoded()));
System.out.println("---END CERTIFICATE---");
} catch (CertificateEncodingException e) {
e.printStackTrace();
}

Categories

Resources