Android self-signed client side CA certificate authentication fails, Can anyone share their experience dealing with similar issues? With the same credentials we are able to get it to work using CURL client.
We followed this GIST however we could not get through it.
Following it just led us to have this exception gets thrown:
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:374)
Try the following code
// Input stream for self signed CA certificate
InputStream caIs = getInputStream(caCert);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(caIs);
String alias = certificate.getSubjectX500Principal().getName();
Log.d(TAG, String.format("Alias: %s", alias));
// KeyStore for trusted CA certificate(s)
KeyStore trustedStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustedStore.load(null);
trustedStore.setCertificateEntry(alias, certificate);
// Create trust managers to be used for connecting to servics(s)
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustedStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
// KeyStore for X.509 certificate/key
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream clientIs = getInputStream(clientKeyCert);
keyStore.load(clientIs, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, "password".toCharArray());
// Create key managers to be uses for connecting to service(s)
KeyManager[] keyManagers = kmf.getKeyManagers();
// Create the SSL context
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
// Test by connecting ta server proteced by self signed certificate
OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory()).build();
Call call = client.newCall(new Request.Builder().url("https://testurl.com").build());
Response response = call.execute();
Log.d(TAG, response.message());
Related
My app connects to mqtt broker using certificate file through ssl connection.
I setup the certificate file (.crt) and the key file (.key) in my broker.
I use Paho Mqtt Client api, and this api needs a SSLSocketFactory to establish connection.
I use a Google example to create a SSLSocketFactory instance with a TrustManager who trust our CA in a keystore.
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(new
FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} 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);
Everything works fine right now. BUT, the certificate is going to expire in 5/30/2017.
How do i must deal with the certificate in the client side (Android)?
I've have tested in testing environment with a new certificate. The app can't connect to broker. Exception is:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
How can a deal with certificate renewal on Android?
I have request a new certificate using the same .key file and all clients did not have any issue connecting to broker with the new .crt.
But, is it safe to use the same key for certificate renewal?
It throws an exception like below
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
This Android program connects to my ASP.NET MVC deployed on IIS , and I create the .csr , .key , .crt file of my CA and my server's certificate using OpenSSL.
And I convert the .crt file of my server's certificate to .pfx format and import it in IIS .
I found the solution on Android Developer .But my code is similar to the code it lists .
CertificateFactory cf = CertificateFactory.getInstance("X.509","BC");
InputStream caInput = getResources().openRawResource(R.raw.root); //here "R.raw.root" is a .bks file converted from my CA's .crt file , and a .bks file converted from my server's .crt file , but both throw this exception
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("BKS");
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
URL url = new URL("https://172.18.13.178:63123/Home/Test");
HttpsURLConnection urlConnection =(HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
//omit other code
}
The Android Developer says this is the solution of this error , but I write my code similar to it , but it fails.
So anyone tell me where the problem is ? The way Android Develop gives does not work .
Hi I'm trying to establish ssl communication between tomcat server and android app using https
1- I used keytool to create a keystore file for tomcat
2- then generate a pem file to use it with keytool to generate a BKS file
3- the tomcat server is working fine
basically I followed this article
The problem is when I try to Connect from android app using HttpsURLConnection I always get the exception :
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:351)
at com.android.okhttp.Connection.upgradeToTls(Connection.java:1323)
at com.android.okhttp.Connection.connect(Connection.java:1225)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:395)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:298)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:399)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:110)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:221)
at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25)
at org.apache.cordova.rest.Rest.send(Rest.java:177)
help !!
Two possible solution
1) If you are using Self Signed Certificate try adding the certificate (.crt / .cer) to the truststore.
2) If your certificate is signed by your local CA make sure you import the root CA and intermediate CA to the trust store.
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getApplicationContext().getResources()
.openRawResource(R.raw.my_certificate);//new BufferedInputStream(is);
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);
and finally set the sslcontext to your HttpsURLConnection
I have my own PKI infrastructure for my web server with a CA and an intermediate CA. Then I have a web certificate signed by the intermediate CA and I want my app to communicate with the server. According to the Developer docs the solution is to create my own keystore. So I bundled the root CA certificate with the app and tried to see if that would work. It didnt, and I got the following error:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
So my question is this. Since the SSL certificate is signed by my intermediate CA, is that the certificate I should be importing into the custom key store, or do I need both, or is there something else wrong here?
Ultimately, with a SSL certificate signed by a CA not trusted by Android, is this the right way to go about it?
Thanks!
Here's the code that sets up the keystore manager.
public SSLContext getTrusted() throws Exception{
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
AssetManager assManager = context.getAssets();
InputStream is = null;
try {
is = assManager.open("ca.cert.crt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
InputStream caInput = new BufferedInputStream(is);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.d("TrustMan", "ca=" + ((X509Certificate) ca).getSubjectDN());
} 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);
return context;
}
And then I am trying to use it as follows.
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
TrustMan tm = new TrustMan(context);
SSLContext sslContext;
sslContext = tm.getTrusted();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
The code did actually work, but not when I returned the SSLContext from my class. I adjusted the class to return the TrustManagerFactory instead, and using the intermediate CA certificate works fine now!
Thanks!
I 'm trying to Secure my TCP/IP based Socket connection using SSL for Android platform.
here is some snippet from my code:
Client Side:
SSLSocketFactory sslFact = null;
SSLContext ctx;
KeyStore ks;
char[] passphrase = "hosttest".toCharArray();
ks = KeyStore.getInstance("BKS");
ks.load(SSLActivity.mContext.getResources().openRawResource(R.raw.hosttestcert), passphrase);
TrustManagerFactory tmf =TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
ctx = SSLContext.getInstance("TLS");
ctx.init(null,tmf.getTrustManagers(), null);
sslFact = ctx.getSocketFactory();
mySocket = (SSLSocket)sslFact.createSocket();
mySocket.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 7891),1000);
Server Side:
SSLServerSocketFactory sslSrvFact = null;
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
// Load the self-signed server certificate
char[] passphrase = "hosttest".toCharArray();
ks = KeyStore.getInstance("BKS");
ks.load(SSLActivity.mContext.getResources().openRawResource(R.raw.hosttestcert), passphrase);
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, passphrase);
// Create a SSLContext with the certificate
ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(),null, null);
sslSrvFact = ctx.getServerSocketFactory();
myServerSocket =(SSLServerSocket)sslSrvFact.createServerSocket(port);
When I call the accept() socket call from server, I'm getting the following exception:
javax.net.ssl.SSLException: Could not find any key store entries to support the enabled cipher suites.
org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl.checkEnabledCipherSuites(OpenSSLServerSocketImpl.java:241)
org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl.accept(OpenSSLServerSocketImpl.java:186)
at com.aricent.ssltesst.ApplinkTCPServer$1.run(ApplinkTCPServer.java:189)
at java.lang.Thread.run(Thread.java:856)
I'm following this post for generating my certs and keystore:
http://randomizedsort.blogspot.in/2010/09/step-to-step-guide-to-programming.html
please suggest if I'm missing something or something else needs to be done for the keystore on Android platform.
Not sure if you have the same logic with what I did, in my application I have 1 JKS Keystore generated, which then I used a converter to duplicate a copy of BKS keystore for Android. If this is what you're doing, here's my Server Side codes:
String keyStorePath = "absolute path to your JKS keystore file";
String keyStorePass = "keystore password";
System.setProperty("javax.net.ssl.keyStore", keyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket serverSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port_number);
while (true) {
new ClientThread((SSLSocket) serverSocket.accept()).start();
}