Load specific certificate in Java from worklight - java

I have a worklight project that has an adapter which connects to the services to grab the response.
It uses the worklight keystore that we have created for our project which has the cert required to connect to the backend (cert name : *.company.com) and the keystore (myproject.p12) has the cert in it:
ssl.keystore.path = /was85/.../myproject.p12.
ssl.keystore.pass = Pass
ssl.keytore.type = PKCS12
once I get the response back from the adapter, inside it I have URI that I need to use to grab an image from the web services and convert it to base64.
I'm use a custom Java code to accomplish this:
package com.company.myProject;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.MalformedInputException;
import java.security.Security;
import java.util.logging.Logger;
public class ImageEncoder {
public final static Logger logger = Logger.getLogger(ImageEncoder.class.getName());
public static String getImage(String imageUrl)
throws MalformedURLException, IOException {
String imageDataString = "";
URL url = null;
URLConnection con = null;
try {
url = new URL(imageUrl);
logger.info("url "+url);
con = url.openConnection();
logger.info("con "+con);
InputStream input = con.getInputStream();
logger.info("input " + input);
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(input);
logger.info("bytes " + bytes);
input.close();
imageDataString = encodeImage(bytes);
logger.info("imageDataString " + imageDataString);
return imageDataString;
} catch (MalformedInputException malformedInputException) {
malformedInputException.printStackTrace();
imageDataString = malformedInputException.toString();
logger.info("MalformedInputException malformedInputException " + imageDataString);
return ("exception while reading the imag <" + imageDataString + ">");
} catch (IOException ioException) {
ioException.printStackTrace();
imageDataString = ioException.toString();
logger.info("IOException ioException " + imageDataString);
return ("exception while reading the imag <" + imageDataString + ">");
}
}
public static String encodeImage(byte[] imageData) {
// TODO Auto-generated method stub
org.apache.commons.codec.binary.Base64 base = new org.apache.commons.codec.binary.Base64(
false);
return base.encodeToString(imageData);
// return
// org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(imageData);
}
}
However, the Java code once it opens the connection it complains about the certification (*.company.com) and gives this error:
The signer may need to be added to local trust store "/was85/profiles/node1/config/cells/cell_was/ecommerce_trust.p12" located in SSL configuration alias "DefaultSystemProperties" loaded from SSL configuration file "System Properties". The extended error message from the SSL handshake exception is: "PKIX path building failed: java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl could not build a valid CertPath.; internal cause is:
java.security.cert.CertPathValidatorException: The certificate issued by CN=AddTrust External CA Root, OU=AddTrust External TTP Network, O=AddTrust AB, C=SE is not trusted; internal cause is:
java.security.cert.CertPathValidatorException: Certificate chaining error".
And after investigating it is checking the JVM trust store and not our project trust store.
To resolve this issue I have three options:
Add the root cert which is (AddTrust) to myProject.p12 and not my
leaf cert (*.company.com) which is not accepted.
Add the leaf cert (*.company.com) to the JVM keystore
(ecommerce_trust.p12) which is not acceptable as we have another app
running on the same JVM and it will get access to the leaf cert.
Make a trustManager in my java code to get the project p12 and not
the JVM one which has the following code:
try {
url = new URL(imageUrl);
logger.info("url "+url);
KeyStore trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(new FileInputStream("/was85/resources/security/ecommerce_gr_mobile.p12"), "Pass".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, tms, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
logger.info("con "+con);
//con.setSSLSocketFactory(sslFactory);
InputStream input = con.getInputStream();
logger.info("input " + input);
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(input);
logger.info("bytes " + bytes);
input.close();
imageDataString = encodeImage(bytes);
logger.info("imageDataString " + imageDataString);
//return imageDataString;
} catch (MalformedInputException malformedInputException) {
malformedInputException.printStackTrace();
imageDataString = malformedInputException.toString();
logger.info("MalformedInputException malformedInputException " + imageDataString);
return ("exception while reading the imag <" + imageDataString + ">");
} catch (IOException ioException) {
ioException.printStackTrace();
imageDataString = ioException.toString();
logger.info("IOException ioException " + imageDataString);
return ("exception while reading the imag <" + imageDataString + ">");
} catch (KeyStoreException keyStoreException) {
// TODO Auto-generated catch block
keyStoreException.printStackTrace();
imageDataString = keyStoreException.toString();
logger.info("keyStoreException " + imageDataString);
} catch (NoSuchAlgorithmException noSuchAlgorithmException) {
// TODO Auto-generated catch block
noSuchAlgorithmException.printStackTrace();
imageDataString = noSuchAlgorithmException.toString();
logger.info("noSuchAlgorithmException " + imageDataString);
} catch (CertificateException certificateExceptione) {
// TODO Auto-generated catch block
certificateExceptione.printStackTrace();
imageDataString = certificateExceptione.toString();
logger.info("certificateExceptione " + imageDataString);
} catch (KeyManagementException keyManagementException) {
// TODO Auto-generated catch block
keyManagementException.printStackTrace();
imageDataString = keyManagementException.toString();
logger.info("keyManagementException " + imageDataString);
}
return imageDataString;
}
which is not working and I'm getting this error:
[9/2/15 13:40:09:512 EDT] 0000021d ImageEncoder I >>>>>>>>>>>>>>>trustStore loaded <<<<<<<<<<java.security.KeyStore#f1c4b946
[9/2/15 13:40:09:512 EDT] 0000021d ImageEncoder I >>>>>>>>>>>>>>>tmf init <<<<<<<<<<javax.net.ssl.TrustManagerFactory#4d3fb9ab
[9/2/15 13:40:09:513 EDT] 0000021d ImageEncoder I >>>>>>>>>>>>>>>tms init <<<<<<<<<<[Ljavax.net.ssl.TrustManager;#c76fa980
[9/2/15 13:40:09:513 EDT] 0000021d ImageEncoder I >>>>>>>>>>>>>>>sslContext <<<<<<<<<<
[9/2/15 13:40:09:570 EDT] 0000021d ImageEncoder I con com.ibm.net.ssl.www2.protocol.https.e:https://domain.company.com/wps/wcm/connect/e77f32e8-906f-445f-b198-e3b77cb0e786/logo90x40.gif?MOD=AJPERES&CACHEID=e77f32e8-906f-445f-b198-e3b77cb0e786
[9/2/15 13:40:09:676 EDT] 0000021d ImageEncoder I IOException ioException javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

Worklight server uses the keystore defined by "ssl.keystore.*" to create SSL connection between adapter and backend server configured in adapter's XML file, so if you have custom java code with your own connection you should to set your own SSL context as you do in your example above. It is the right way.
The reason of the error might be the keystore "/was85/resources/security/ecommerce_gr_mobile.p12" doesn't contain the cert of the images server.
I suggest to create separate kestore and use it from adapter's java code. Put into it all certs of the servers you want to reach from adapter's java code.

I was able to resolve the issue by adding:
con.connect();
The complete code will be:
KeyStore trustStore = KeyStore.getInstance("PKCS12");
File key = new File ("/was85/resources/security/ecommerce_gr_mobile.p12");
trustStore.load(new FileInputStream(key), "Pass".toCharArray());
logger.info(">>>>>>>>>>>>>>>trustStore loaded <<<<<<<<<<" + String.valueOf(trustStore) );
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
logger.info(">>>>>>>>>>>>>>>tmf init <<<<<<<<<<" + String.valueOf(tmf));
TrustManager[] tms = tmf.getTrustManagers();
logger.info(">>>>>>>>>>>>>>>tms init <<<<<<<<<<" + String.valueOf(tms));
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLS");
logger.info(">>>>>>>>>>>>>>>sslContext <<<<<<<<<<");
sslContext.init(null, tms, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.connect();
logger.info("con "+con);
//con.setSSLSocketFactory(sslFactory);
InputStream input = con.getInputStream();
logger.info("input " + input);
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(input);
logger.info("bytes " + bytes);
input.close();

Related

Received fatal alert, bad_certificate

I am trying to make an SSL conection to a server. I have created a Truststore and imported the server's certificate as well as mine as trusted entries into the Keystore. The server guys also have imported my certificate into their keystore. But when i try to connect, i get this error:
Received fatal alert: bad_certificate
On the server, they are getting this error:
javax.net.ssl.SSLHandshakeException: null cert chain
What could i be possibly be doing wrong?, How do i fix this error? I have been battling this issue for a very long time now.
My Client Code
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Enumeration;
import javax.net.ssl.*;
public class SSLConnect {
public String MakeSSlCall(String meternum) {
String message = "";
FileWriter file = null;
try {
file = new FileWriter("C:\\SSLCERT\\ClientJavalog.txt");
} catch (Exception ee) {
message = ee.getMessage();
}
//writer = new BufferedWriter(file );
try {
file.write("KeyStore Generated\r\n");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("C:\\SSLCERT\\newclientkeystore"), "client".toCharArray());
file.write("KeyStore Generated\r\n");
Enumeration enumeration = keystore.aliases();
while (enumeration.hasMoreElements()) {
String alias = (String) enumeration.nextElement();
file.write("alias name: " + alias + "\r\n");
keystore.getCertificate(alias);
file.write(keystore.getCertificate(alias).toString() + "\r\n");
}
TrustManagerFactory tmf =TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
file.write("KeyStore Stored\r\n");
SSLContext context = SSLContext.getInstance("SSL");
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
SSLSocketFactory f = context.getSocketFactory();
file.write("About to Connect to Ontech\r\n");
SSLSocket c = (SSLSocket) f.createSocket("192.168.1.16", 4447);
file.write("Connection Established to 196.14.30.33 Port: 8462\r\n");
file.write("About to Start Handshake\r\n");
c.startHandshake();
file.write("Handshake Established\r\n");
file.flush();
file.close();
return "Connection Established";
} catch (Exception e) {
try {
file.write("An Error Occured\r\n");
file.write(e.getMessage() + "\r\n");
file.flush();
file.close();
} catch (Exception eee) {
message = eee.getMessage();
}
return "Connection Failed";
}
}
}
Keytool commands for creating my truststore
keytool -import -alias client -file client.cer -keystore MyKeystore -storepass mystore
keytool -import -alias server -file server.cer -keystore MyKeystore -storepass mystore
And i have also added the two certificates to my cacerts keystore
It's been a while, but I had to face similar issue. Here is my working code:
Properties systemProps = System.getProperties();
systemProps.put("javax.net.debug","ssl");
systemProps.put("javax.net.ssl.trustStore","<path to trustore>");
systemProps.put("javax.net.ssl.trustStorePassword","password");
System.setProperties(systemProps);
SSLContext sslcontext;
KeyStore keyStore;
final char[] JKS_PASSWORD = "password".toCharArray();
final char[] KEY_PASSWORD = "password".toCharArray();
try {
final InputStream is = new FileInputStream("<path_to_keystore.pkcs12>");
keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(is, JKS_PASSWORD);
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, KEY_PASSWORD);
sslcontext=SSLContext.getInstance("TLS");
sslcontext.init(kmf.getKeyManagers(), null, new java.security.SecureRandom());
} catch (Exception ex) {
throw new IllegalStateException("Failure initializing default SSL context", ex);
}
SSLSocketFactory sslsocketfactory = sslcontext.getSocketFactory();
DataOutputStream os = null;
try {
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket();
sslsocket.connect(new InetSocketAddress(host, port), connectTimeout);
sslsocket.startHandshake();
os = new DataOutputStream(sslsocket.getOutputStream());
// log.info("Sending echo packet");
String toSend = "{\"echo\":\"echo\"}";
os.writeBytes(toSend);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Android SSL SNI connection issues

I have an app that serves to consume and update data to a webserver and, recently, the app owner decided to switch to a secure connection due to personal information stored.
The server is already set up as SNI and I have checked it using digicert, the server is working fine and seems to be set up correctly, but does not include the path *.host.com on its alternate names (I am unsure if this is normal or not for SNI).
The iOS worked like a charm, however on Android I get this error:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
My current connection method looks like this:
URL url = new URL(postURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
String userpass = "bob" + ":" + "12345678";
String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
conn.setRequestProperty("Authorization", basicAuth);
conn.setReadTimeout(7000);
conn.setConnectTimeout(7000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.connect();
InputStream instream = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
StringBuilder everything = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
everything.append(line);
}
JSONObject jsonObject = new JSONObject(everything.toString());
return jsonObject;
I'm not quite sure what's the issue here, but trying to connect to https://sni.velox.ch/ gives me a long answer that seems like a success.
Also, I do have the pem key for the certificate here with me, but I do not know how I add that in this context.
Usually you get this error when using a self-signed certificate, in which case you would have to use the certificate while making the request.
Additionally, you might be getting this error because of not including the path *.host.com.
You could try the below code to pass your certificate while building the HttpsURLConnection. Please don't forget to copy the ca.pem file to assets folder.
private HttpsURLConnection buildSslServerConnection() {
HttpsURLConnection urlConnection = null;
try {
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(context.getAssets().open("ca.pem"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Authorization", "Basic" + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT));
urlConnection.setConnectTimeout(7000);
urlConnection.setReadTimeout(7000);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setUseCaches(false);
urlConnection.setAllowUserInteraction(false);
urlConnection.setDoOutput(false);
} catch (KeyManagementException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (CertificateException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (FileNotFoundException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (KeyStoreException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (NoSuchAlgorithmException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (MalformedURLException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (IOException e) {
LOG.error("Error while checking server connectivity: ", e);
}
return urlConnection;
}
Hope this helps.

Android connect to server with selfsigned certificate

EDITTED: "The code below works fine, no errors, no exceptions"
I'm aware of the grand amount of questions in regards to this topic, as well as the many blogs that google conjures up. I have read through them and have managed to come up with what I'm about to explain. My doubt lies in "is my approach correct? Does it have any side-effects?" and another question that is better asked as I explain my method.
I based this approach following this Android.Developres tutorial.
System.setProperty("jsse.enableSNIExtension", "false");
//Java 7 introduced SNI (enabled by default). The server I use is
// misconfigured I suppose and
// it sends an "Unrecognized Name" warning in the SSL handshake
// which breaks my web service.
// Load CA from an InputStream (CA would be saved in Raw file,
// and loaded as a raw resource)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(new FileInputStream("PATH_TO_CERT.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Create all-trusting host name verifier
// to avoid the following :
// java.security.cert.CertificateException: No name matching
// This is because Java by default verifies that the certificate CN (Common Name) is
// the same as host name in the URL. If they are not, the web service client fails.
HostnameVerifier allHostsValid = new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
//Install it
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https....");
urlConnection.setSSLSocketFactory(context.getSocketFactory());
try {
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
switch(urlConnection.getResponseCode()){
case 401:
BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getErrorStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line+"\n");
}
br.close();
System.out.println( sb.toString());
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Here is my other question, in the following line:
InputStream caInput = new BufferedInputStream(new FileInputStream("PATH_TO_CERT.crt"));
You see that the method forces me to have the certificate.crt preloaded onto raw file inside res folder. Is there a way (I have looked but have found 0 answers) to connect to the server and download said certificate.crt and save it on a private folder not accessible by the user?

Keystore loading

I would like to know what's the equivalent in java of the following :
-Djavax.net.ssl.trustStore=keystore.jks -Djavax.net.ssl.keyStore=keystore.jks
-Djavax.net.debug=ssl -Djavax.net.ssl.keyStorePassword=test JavaFile
I would like to load the keystore otherwise than sending it as arguments from the command line. I've been working with :
private TcpLink createSSL() {
KeyStore keyStore = null;
TrustManagerFactory tmf = null;
SSLContext ctx = null;
SSLSocket socket = null;
TcpLink smscLink = null;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
LOGGER.info("Got keystore");
keyStore.load(new FileInputStream("/root/keystore.jks"), "test".toCharArray());
LOGGER.info("Loaded keystore");
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
LOGGER.info("Inited keystore");
ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();
socket = (SSLSocket)factory.createSocket("100.100.201.189", 8807);
LOGGER.info("Got socket");
smscLink = new TcpLink(socket);
return smscLink;
} catch (KeyStoreException e) {
LOGGER.error("Key store exception : " + e);
} catch (NoSuchAlgorithmException e) {
LOGGER.error("NoSuchAlgorithmException : " + e);
} catch (CertificateException e) {
LOGGER.error("CertificateException : " + e);
} catch (FileNotFoundException e) {
LOGGER.error("FileNotFoundException : " + e);
} catch (IOException e) {
LOGGER.error("FileNotFoundException : " + e);
} catch (KeyManagementException e) {
LOGGER.error("KeyManagementException : " + e);
} catch (Exception e) {
LOGGER.error("Exception : " + e);
}
return null;
}
but I get :
javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1293)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:65)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
Any ideas are welcome !
Thx
You can set the System properties this way:
System.setProperty("javax.net.ssl.keyStore", '/path/to/keystore.jks');
System.setProperty("javax.net.ssl.keyStorePassword", 'your-password-here');
They will be used system-wide (in this instance of JVM), so probably you want to do it at initialisation time.
It works using this piece of code :
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(this.getCertificateContent(), "test".toCharArray());
kmf.init(keyStore, "test".toCharArray());
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLSv1");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();
socket = (SSLSocket)factory.createSocket("100.125.100.1", 8775);
If you want, here's an API to create SSLSocket and SSLServerSocket easyly:
https://github.com/gpotter2/SSLKeystoreFactories
It does not require any other jars.... just get the files and use them like:
SSLSocket s = SSLSocketKeystoreFactory.getSocketWithCert(ip, port, Main.class.getResourceAsStream("/mykey.jks"), "password")
Or:
SSLServerSocket s = SSLServerSocketKeystoreFactory.getSocketWithCert(port, Main.class.getResourceAsStream("/mykey.jks"), "password")
That's much easier to use :)

SSL connection failure between java server and android client

I am trying to setup mutual authentication SSL connection between java host and android client. Don't know why its not getting connected. Below are the code of Android client app and Java server.
Client code:
private SSLContext createSSLContext(final Context cont){
SSLContext ssl_cont = null;
try {
Log.d(TAG, "TrustStore - Initializing");
KeyStore trustStore = KeyStore.getInstance("BKS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
InputStream trustStoreStream = cont.getResources().openRawResource(R.raw.myclienttruststore);
trustStore.load(trustStoreStream, "client".toCharArray());
trustManagerFactory.init(trustStore);
Log.d(TAG, "TrustStore - Initialized");
// Setup keystore
Log.d(TAG, "KeyStore - Initializing");
KeyStore keyStore = KeyStore.getInstance("BKS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
InputStream keyStoreStream = cont.getResources().openRawResource(R.raw.myclient);
keyStore.load(keyStoreStream, "client".toCharArray());
keyManagerFactory.init(keyStore, "client".toCharArray());
Log.d(TAG, "KeyStore - Initialized");
ssl_cont = SSLContext.getInstance("TLS");
ssl_cont.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
} catch (Exception e) {
// TODO Auto-generated catch block
alertbox("SSLClient", "ERROR: " + e.getMessage());
Log.d(TAG, "ERROR: " + e.getMessage());
}
return ssl_cont;
}
OnClickListener onConnClick = new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
try {
// Setup the SSL context to use the truststore and keystore
Log.d(TAG, "Started..");
SSLContext ssl_context = createSSLContext(cont);
Log.d(TAG,"here 1...");
SSLSocketFactory socketFactory = (SSLSocketFactory) ssl_context.getSocketFactory();
Log.d(TAG,"here 2...");
socket = (SSLSocket) socketFactory.createSocket(ipadd.getText().toString().trim(), Integer.parseInt(port.getText().toString().trim()));
Log.d(TAG,"here 3...");
dataOut = new DataOutputStream(socket.getOutputStream());
dataIn = new DataInputStream(socket.getInputStream());
dataOut.writeUTF("Hello !!");
msgin.setText("Connected");
Log.d(TAG, "Completed..");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
msgin.setText("Not connected");
alertbox("Main", "ERROR: " + e.getMessage());
Log.d(TAG, "ERROR: " + e.getMessage());
}
}
};
Server code:
try {
mySSLServerFac = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
mySSLServerSocket = (SSLServerSocket) mySSLServerFac.createServerSocket(9999);
System.out.println("Listening on 9999\n");
mySSLSocket = (SSLSocket) mySSLServerSocket.accept();
DataInputStream input = new DataInputStream(mySSLSocket.getInputStream());
DataOutputStream output = new DataOutputStream(mySSLSocket.getOutputStream());
do{
System.out.println("Remote IP Address : " + mySSLSocket.getInetAddress());
msg = input.readUTF().toString();
System.out.println(msg);
java.util.Scanner sc = new java.util.Scanner(System.in);
output.writeUTF(sc.nextLine());
}while(msg != "exit");
System.out.println(msg);
} catch (Exception e) {
e.printStackTrace();
}
I am stuck with "No cipher suites in common" error at server. Since i am nowhere in SSL connection setup. Let me help if you find out the bug or major problem.
Here is the link i followed to create certificate and truststore. Truststore and kestore i have created are here
I am using Android 2.2 and BKSProvider 1.46, please let know where i am going wrong. I have to wind up this project as soon as possible.
Thanks in advance.
From the stack trace it looks like exception you caught does not contain a message.
Log.d(TAG, e.getMessage());
It has nothing to do with SSL.
It's solved ! Problem was with the truststore of java host, followed this post.
The trustStore needs to be specified for client/server as they are using the default trustStore, causing failure. Using -Djavax.net.ssl.trustStore=servertruststore.jks -Djavax.net.ssl.trustStorePassword=server on the server and creating own keystore & truststore at client allows the session to complete. It was the -Djavax.net.debug=ssl,handshake which helped lot.
The entire command is : java -Djavax.net.ssl.keyStore=server.jks -Djavax.net.ssl.keyStorePassword=server -Djavax.net.ssl.trustStore=servertruststore.jks -Djavax.net.ssl.trustStorePassword=server SSLServer
Now i am on to creating sslsession and multi-threaded programming.

Categories