SSL Socket Connection Error - java

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
]

Related

Using Eclipse To Connect To Network

I want to connect my Eclipse plug-in to an HTTPS URL, but have a problem because the user would need to accept the certificate. Of course there are a couple of tutorials for how to do this in plain Java, but that might be hard to do inside an Eclipse plug-in and I think I'd reinvent the wheel that way.
Because Eclipse has some built in tooling to connect to sites with different network protocols. An example would be the "Install new Software..." action. The tooling even has a preference page that lists HTTPS separately.
According to the Eclipse Help, the KeyStore is used "as a repository for Certificates used for trust decisions [...] when making SSL connections". Yet I couldn't figure out how to use it.
So my question is: How do I use the Eclipse's build in facilities to connect to my HTTPS site?
Based on this answer here I build my own plug-in which loads just the one certificate I need (lucky me) in its EarlyStartup:
public class EarlyStartup implements IStartup {
private static final String ALIAS = "ACME";
#Override
public void earlyStartup() {
final char[] passphrase = "changeit".toCharArray();
final char separator = File.separatorChar;
final File dir = new File(System.getProperty("java.home") + separator + "lib" + separator + "security");
final File file = new File(dir, "cacerts");
try (InputStream certIn = getClass().getResourceAsStream("acme.org.crt");
final InputStream localCertIn = new FileInputStream(file);) {
final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(localCertIn, passphrase);
if (keystore.containsAlias(ALIAS)) {
return;
}
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final Certificate cert = cf.generateCertificate(certIn);
keystore.setCertificateEntry(ALIAS, cert);
try (OutputStream out = new FileOutputStream(file)) {
keystore.store(out, passphrase);
}
} catch (final Exception e) {
e.printStackTrace();
}
}
}

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);
}
}

Java, jsch and EC2...can't run an application in root

I'm connecting to an EC2 instance from a remote machine via Java and Jsch. Once connected, I want to start a jboss server that sits in a directory owned and created by root. (I can't change that).
Usually from my putty shell, I would start jboss by issuing the following commands:
myUser#myIP:~# sudo su -
root#myIP:~:# cd jbossDirectory
root#myIp:~/jbossDirectory# ./startJbossScript.sh
The problems start when I try to do the same via Java/Jscp. This is my code:
import java.io.InputStream;
import java.io.OutputStream;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
public class SSHExecutor {
static String SSHprivateKey = privateKeyFileLocation;
static String username = myUser;
static String hostnamePublicIP = EC2InstanceIP;
static String startJbossCommand = "sudo -i /root/jbossDirectory/startJbossScript.sh";
static String sudo_pass = "";
public static void main(String[] arg) {
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
try {
JSch jsch = new JSch();
jsch.addIdentity(SSHprivateKey);
Session session = jsch.getSession(username, hostnamePublicIP, 22);
// username and passphrase will be given via UserInfo interface.
UserInfo ui = new MyUserInfo();
session.setUserInfo(ui);
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(startJbossCommnand);
InputStream in = channel.getInputStream();
OutputStream out = channel.getOutputStream();
((ChannelExec) channel).setErrStream(System.err);
channel.connect();
out.write((sudo_pass + "\n").getBytes());
out.flush();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
System.out.print(new String(tmp, 0, i));
}
if (channel.isClosed()) {
System.out.println("exit-status: "
+ channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
channel.disconnect();
session.disconnect();
} catch (Exception e) {
System.out.println(e);
}
}
}
This program will correctly starts Jboss. However, when Jboss receives a request for a dynamic page, it throws the following error:
06:48:13,137 INFO [STDOUT] >>>>>>>>/root/.
06:8:13,138 INFO [STDOUT] Exception while initializing hibernate: java.io.FileNotFoundException: WEBAPP_CONF/hibernate.properties (No such file or directory)
06:48:13,141 INFO [[/rubis]] Marking servlet BrowseRegions as unavailable
06:48:13,141 ERROR [[BrowseRegions]] Allocate exception for servlet BrowseRegions
javax.servlet.UnavailableException: Couldn't find file mysql.properties: java.io.FileNotFoundException: WEBAPP_CONF/mysql.properties (No such file or directory)<br>
at edu.rice.rubis.servlets.RubisHttpServlet.init(Unknown Source)
at edu.rice.rubis.servlets.HibernateRubisHttpServlet.init(Unknown Source)
at javax.servlet.GenericServlet.init(GenericServlet.java:212)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:806)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:129)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
at java.lang.Thread.run(Thread.java:724)
So it appears that it can't find the mysql configuration file. The file is there and this issue does not happen when I launch jboss from the console (as showed above). My guess is that the process does start with the sudo -i command, but then, it can't access the files that are within the jbossDirectory folder, hence it throws the error file not found. The WEBAPP_CONF/ is a subdirectory of jbossDirectory.
Any idea on how to fix this?
Thank you.
You are running the shell script from a different directory, and there is something in your code that expects the start-up script to start specifically in /root/jbossDirectory.
A simple workaround would be to edit startJbossScript.sh and add
cd /root/jbossDirectory
as the first line.
Before the channel.connect() line in your code add the below line which will allow you to excecute sudo commands
((ChannelExec) channel).setPty(true);

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.

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

I am using Retrofit to access my REST API. However, when I put my API behind ssl and access it by http://myhost/myapi then I get this error:
Do I need to do something extra now that my API is behind SSL?
Here is how I connect:
private final String API = "https://myhost/myapi";
private final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
.setServer(API)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
01-10 09:49:55.621 2076-2100/com.myapp.mobile D/Retrofit﹕ javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:401)
at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
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.getResponseCode(HttpURLConnectionImpl.java:497)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
at $Proxy12.signin(Native Method)
at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:143)
at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:136)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:282)
at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:595)
at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:398)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            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.getResponseCode(HttpURLConnectionImpl.java:497)
            at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
            at $Proxy12.signin(Native Method)
            at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:143)
            at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
The reason this occur is the JVM/Dalvik haven't not confidence in the CA certificates in the system or in the user certificate stores.
To fix this with Retrofit, If you are used okhttp, with another client it's very similar.
You've to do:
A). Create a cert store contain public Key of CA. To do this you need to launch next script for *nix.
You need openssl install in your machine, and download from https://www.bouncycastle.org/ the jar bcprov-jdk16-1.46.jar. Download this version not
other, the version 1.5x is not compatible with android 4.0.4.
#!/bin/bash
if [ -z $1 ]; then
echo "Usage: cert2Android<CA cert PEM file>"
exit 1
fi
CACERT=$1
BCJAR=bcprov-jdk16-1.46.jar
TRUSTSTORE=mytruststore.bks
ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT`
if [ -f $TRUSTSTORE ]; then
rm $TRUSTSTORE || exit 1
fi
echo "Adding certificate to $TRUSTSTORE..."
keytool -import -v -trustcacerts -alias $ALIAS \
-file $CACERT \
-keystore $TRUSTSTORE -storetype BKS \
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath $BCJAR \
-storepass secret
echo ""
echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE..."
B). Copy the file truststore mytruststore.bks in res/raw of your project
C). Setting SSLContext of the connection:
.............
okHttpClient = new OkHttpClient();
try {
KeyStore ksTrust = KeyStore.getInstance("BKS");
InputStream instream = context.getResources().openRawResource(R.raw.mytruststore);
ksTrust.load(instream, "secret".toCharArray());
// TrustManager decides which certificate authorities to use.
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ksTrust);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {
e.printStackTrace();
}
.................
This can happen for several reasons, including:
The CA that issued the server certificate was unknown
The server certificate wasn't signed by a CA, but was self signed
The server configuration is missing an intermediate CA
please check out this link for solution: https://developer.android.com/training/articles/security-ssl.html#CommonProblems
Fix for Android N & above:
I had similar issue and mange to solve it by following steps described in https://developer.android.com/training/articles/security-config
But the config changes, without any complicated code logic, would only work on Android version 24 & above.
Fix for all version, including version < N:
So for android lower then N (version 24) the solution is to via code changes as mentioned above. If you are using OkHttp, then follow the customTrust:
https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java
You basically have four potential solutions to fix a "javax.net.ssl.SSLHandshakeException: " exception on Android
Trust all certificates. Don't do this, unless you really know what you're doing.
Create a custom SSLSocketFactory that trusts only your certificate. This works as long as you know exactly which servers you're going to connect to, but as soon as you need to connect to a new server with a different SSL certificate, you'll need to update your app.
Create a Keystore file that contains Android's "master list" of certificates, then add your own. If any of those certs expire down the road, you are responsible for updating them in your app. I can't think of a reason to do this.
Create a custom SSLSocketFactory that uses the built-in certificate KeyStore, but falls back on an alternate KeyStore for anything that fails to verify with the default.
This is well explained in click here
Also, I want to elaborate more to point number 1.
We can selectively skip some domain using manifest network config as explain:
Create a file "network_security_config.xml" in xml folder in res folder with following content.
<network-security-config xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<domain-config>
<domain includeSubdomains="true">191.1.1.0</domain>
<domain includeSubdomains="true">your_domain</domain>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</domain-config>
</network-security-config>
Add "network_security_config.xml" to application tag in manifest as:
android:networkSecurityConfig="#xml/network_security_config"
Thats it..done!!. You successfully skipped the SSL certificate.
There are 4 ways that I know of:
import the certificate to your app and use it for the connection
disable certificate checking
add your certificate to the trusted system certificates in Android
buy a verified certificate that is accepted by Android
I assume you don't want to pay for this, so I think the most elegant solution is the first one, what can be accomplished this way:
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
The SSL is not properly configured. Those trustAnchor errors usually mean that the trust store cannot be found. Check your configuration and make sure you are actually pointing to the trust store and that it is in place.
Make sure you have a -Djavax.net.ssl.trustStore system property set and then check that the path actually leads to the trust store.
You can also enable SSL debugging by setting this system property -Djavax.net.debug=all. Within the debug output you will notice it states that it cannot find the trust store.
This is a Server-Side issue.
Server side have .crt file for HTTPS, here we have to do combine
cat your_domain.**crt** your_domain.**ca-bundle** >> ssl_your_domain_.crt
then restart.
sudo service nginx restart
For me working fine.
I use this class and have no problem.
public class WCFs
{
// https://192.168.30.8/myservice.svc?wsdl
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "192.168.30.8";
private static final String SERVICE = "/myservice.svc?wsdl";
private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";
public static Thread myMethod(Runnable rp)
{
String METHOD_NAME = "myMethod";
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("Message", "Https WCF Running...");
return _call(rp,METHOD_NAME, request);
}
protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
{
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
int TimeOut = 5*1000;
envelope.dotNet = true;
envelope.bodyOut = soapReq;
envelope.setOutputSoapObject(soapReq);
final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);
try
{
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
{
#Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
});
KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));
}
catch(Exception e){}
HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
{
#Override
public void run()
{
Handler h = new Handler(Looper.getMainLooper());
Object response = null;
for(int i=0; i<4; i++)
{
response = send(envelope, httpTransport_net , METHOD_NAME, null);
try
{if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}
if(response != null)
break;
ThreadHelper.threadSleep(250);
}
if(response != null)
{
if(rp != null)
{
rp.setArguments(response.toString());
h.post(rp);
}
}
else
{
if(Thread.currentThread().isInterrupted())
return;
if(rp != null)
{
rp.setExceptionState(true);
h.post(rp);
}
}
ThreadHelper.stopThread(this);
}
};
thread.start();
return thread;
}
private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
{
try
{
if(headerList != null)
androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
else
androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);
Object res = envelope.getResponse();
if(res instanceof SoapPrimitive)
return (SoapPrimitive) envelope.getResponse();
else if(res instanceof SoapObject)
return ((SoapObject) envelope.getResponse());
}
catch(Exception e)
{}
return null;
}
public static KeyStore getFromRaw(#RawRes int id, String algorithm, String filePassword)
{
try
{
InputStream inputStream = ResourceMaster.openRaw(id);
KeyStore keystore = KeyStore.getInstance(algorithm);
keystore.load(inputStream, filePassword.toCharArray());
inputStream.close();
return keystore;
}
catch(Exception e)
{}
return null;
}
public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustKey);
SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
catch(Exception e){}
return null;
}
}
My answer might not be solution to your question but it will surely help others looking for similar issue like this one:
javax.net.ssl.SSLHandshakeException: Chain validation failed
You just need to check your Android Device's Date and Time, it should be fix the issue.
This resoled my problem.

Categories

Resources