Using the Android TrustStore for aSmack in Android

2019-03-21 17:04发布

问题:

I am not an expert on keystores and have a hard time understanding the nuances of this but this is how far I got:

In creating a xmpp-connection using the asmack build found here one still has to change the truststore, which usually, so say multiple sources on the web, is done using these commands

ConnectionConfiguration config = new ConnectionConfiguration(host, Integer.parseInt(port), service);
config.setTruststorePath("/system/etc/security/cacerts.bks");
config.setTruststorePassword("changeit");
config.setTruststoreType("bks");
XMPPConnection connection = new XMPPConnection(connConfig);
connection.connect();

This works find for older Android versions but under ICS they changed some things and now it does not anymore.The path now is diferent.

Apparently this can be fixed but I have no earthly idea how.

What is needed, obviously, is a method that returns the path depending on SDK version that returns the needed string to set the sdk-path since you can not just return the keystore itself to the xmpp-connection.

In reference to this that method would look like this:

private String getTrustStorePath() 
{
 String path = System.getProperty("javax.net.ssl.trustStore");

 if (path == null) 
 {
  if ( Build.VERSION.SDK_INT >= 14 ) 
  {
   //THIS IS THE PART I DONT KNOW
   path="";
  }
  else
  {
   path = "/system/etc/security/cacerts.bks";
  }

  return path;
}

Here a commenter says that under Android "4.x; /etc/security/cacerts.bks was replaced with the directory/etc/security/cacerts/ containing the certs as individual PEM encoded files." however, I do not know what relevance, if any, this has.

I have also checked out the code of two projects using xmpp and asmack (gtalksms and yaxim but did not see how they avoid this problem.

回答1:

Try this:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    connectionConfiguration.setTruststoreType("AndroidCAStore");
    connectionConfiguration.setTruststorePassword(null);
    connectionConfiguration.setTruststorePath(null);
} else {
    connectionConfiguration.setTruststoreType("BKS");
    String path = System.getProperty("javax.net.ssl.trustStore");
    if (path == null)
        path = System.getProperty("java.home") + File.separator + "etc"
            + File.separator + "security" + File.separator
            + "cacerts.bks";
    connectionConfiguration.setTruststorePath(path);
}

See https://github.com/Flowdalic/asmack/wiki/Truststore and some background explanation at http://nelenkov.blogspot.com/2011/12/ics-trust-store-implementation.html.



回答2:

The trust store in ICS is not in a single .bks file any more, but in separate PEM-encoded files in the /system/etc/security/cacerts directory. User-added certs can be placed in /data/misc/keychain/cacerts-added. More details can be found here.

Your cert file must be named as: subject-hash.N where N is an sequential integer starting from 0 (usually just 0, but if 0 is already used, then 1, etc).

To get the subject-hash of your cert, you can use openssl like this: openssl x509 -noout -subject_hash_old -in my-cert-file.pem