1

I have an application that connects to a server in the local ip network. This connection is TLS encrypted with a custom certificate. Following the guides on this side I made it work under all android version up to android 7. Sadly since Android 7 it is no longer working. Please does anybody know why this is not working anymore?

I found this article and included a network config file with the following code (I know this might not be secure, but first this has to work...):

<network-security-config>  
  <base-config>  
       <trust-anchors>  
            <!-- Only trust the CAs included with the app  
             for connections to internal.example.com -->
            <certificates src="@raw/ca_cert" />
            <certificates src="system"/>
       </trust-anchors>
  </base-config>  
</network-security-config>

Sadly it is still not working. I also added it in the manifest as android:networkSecurityConfig="@xml/network_security_config".

The exception I am getting (Only Android 7+)!

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

This is the code for initializing my SSL Context

// Step 1: Initialize a ssl context with highest version
ssl_ctx = SSLContext.getInstance("TLSv1.2");

// Step 2: Add certificates to context

// Step 2.1 get private key
int pkeyId = context.getResources().getIdentifier("raw/clientkeypkcs", null, context.getPackageName());
InputStream fis = context.getResources().openRawResource(pkeyId);
DataInputStream dis = new DataInputStream(fis);
byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
byte[] key = new byte[bais.available()];
KeyFactory kf = KeyFactory.getInstance("RSA");
bais.read(key, 0, bais.available());
bais.close();           
PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
PrivateKey ff = kf.generatePrivate (keysp);

//Step 2.2 get certificates
int caresId = context.getResources().getIdentifier("raw/ca_cert", null, context.getPackageName());            
InputStream caCertIS = context.getResources().openRawResource(caresId);
CertificateFactory cacf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate)cacf.generateCertificate(caCertIS);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null); // You don't need the KeyStore instance to come from a file.
ks.setCertificateEntry("caCert", caCert);
tmf.init(ks);

int clientresId = context.getResources().getIdentifier("raw/client_cert", null, context.getPackageName());            
InputStream clientCertIS = context.getResources().openRawResource(clientresId);
CertificateFactory clientcf = CertificateFactory.getInstance("X.509");
X509Certificate clientCert = (X509Certificate)clientcf.generateCertificate(clientCertIS);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
ks.setCertificateEntry("clientCert", clientCert);
kmf.init(ks, "***********".toCharArray());
Certificate[] chain = new Certificate[] { clientCert};
//ks.load(null); // You don't need the KeyStore instance to come from a file.
ks.setKeyEntry("importkey", ff, "***********".toCharArray(), chain );           

ssl_ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
findusl
  • 2,454
  • 8
  • 32
  • 51
  • 1
    "This is the code for initializing my SSL Context" -- you do not need any of that to use network security configuration. Beyond that, your XML (`@raw/cacert`) and your Java code (`"raw/ca_cert"`) do not match. Either you have two copies of your certificate (which is a waste), or one (or both) of those are not referring to the correct thing. – CommonsWare May 04 '17 at 16:47
  • The SSL context made it work for Android < 7 so I am kind of hesitant deleting that as you surely understand. If it runs under 7 I might clean up.and yes I have two byte identical files of the ca don't know why – findusl May 04 '17 at 16:51
  • I recommend temporarily not using that code, then see if you have better luck on Android 7.0. If you do, then you can arrange to conditionally use your code on older devices, skipping it on newer ones. – CommonsWare May 04 '17 at 16:55
  • @CommonsWare could the different file be the problem? Can't test right now since the Android 7 is not my device. – findusl May 04 '17 at 16:55
  • "could the different file be the problem?" -- if they have the same contents, AFAIK they should be OK. – CommonsWare May 04 '17 at 17:01
  • @CommonsWare Would you know which part of my code to leave out? I can't just remove everything since I need the private key for connecting. – findusl May 05 '17 at 10:05
  • The `raw/ca_cert` section would duplicate what network system configuration would give you, AFAICT. – CommonsWare May 05 '17 at 11:13

2 Answers2

1

You probably might have the user certificate missing:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>
  • I no longer have access to the application, however this looks very similar to the code that I have written at the start of the question. Can you explain what exactly is different? – findusl Sep 06 '19 at 11:54
  • In the top example you specified a concrete certificate `` There are two kind of trusted credentials `System` and `User`. By including `user` you make sure that any certificate you install manually is gonna be trusted. That way you don't limit your trusted certificate to be just the one you specifically indicate – Fernando Prieto Moyano Sep 06 '19 at 13:28
0

I faced this same issue on Android Oreo device

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

Its due to device date is set to old date for some other test purpose. I never know that could cause this kind of SSLHandshakeException issue. After lot of struggle, i just set device date back to current date. Solved the issue. :D

I think your scenario may be different and need to handle in other way. But I just posted this answer, Just in case it may help somebody.

praveenb
  • 10,549
  • 14
  • 61
  • 83
  • Yeah it seems different from mine and I can't test it anymore had to completely change the approach, so I will not mark it as correct. But if one person lands here and is helped by your answer it will be worth posting :) – findusl Sep 28 '18 at 12:17