2

The android.security.KeyChain#getCertificateChain needs an alias. But I want to get all installed X509Certificate.

crybird
  • 111
  • 1
  • 7

3 Answers3

4

You can use something like this to list trusted certificates. Not exactly documented though, so it might break in future versions.

KeyStore ks = KeyStore.getInstance("AndroidCAStore");
ks.load(null, null);
Enumeration aliases = ks.aliases();
while (aliases.hasMoreElements()) {
    String alias = aliases.nextElement();
    X509Certificate cert = (X509Certificate) 
       ks.getCertificate(alias);
    Log.d(TAG, "Subject DN: " + 
       cert.getSubjectDN().getName());
    Log.d(TAG, "Subject SN: " + 
       cert.getSerialNumber().toString());
    Log.d(TAG, "Issuer DN: " + 
       cert.getIssuerDN().getName());
}
jww
  • 97,681
  • 90
  • 411
  • 885
Nikolay Elenkov
  • 52,576
  • 10
  • 84
  • 84
4

List the available certs:

public void PrintInstalledCertificates( ){

    try 
    {
        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
        if (ks != null) 
        {
            ks.load(null, null);
            Enumeration<String> aliases = ks.aliases();
            while (aliases.hasMoreElements()) 
            {
                String alias = (String) aliases.nextElement();
                java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) ks.getCertificate(alias);

                //To print System Certs only
                if(cert.getIssuerDN().getName().contains(“system”))
                {
                    System.out.println(cert.getIssuerDN().getName());
                }

                //To print User Certs only 
                if(cert.getIssuerDN().getName().contains(“user”))
                {
                    System.out.println(cert.getIssuerDN().getName());
                }

                //To print all certs
                System.out.println(cert.getIssuerDN().getName());                           
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (java.security.cert.CertificateException e) {
        e.printStackTrace();
    }               
}

Check if a certificate is already installed:

public boolean checkCACertificateInstalled(javax.security.cert.X509Certificate x509){

    boolean isCACertificateInstalled = false;

    try 
    {
        String name = x509.getIssuerDN().getName(); 
        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
        if (ks != null) 
        {
            ks.load(null, null);
            Enumeration<String> aliases = ks.aliases();
            while (aliases.hasMoreElements()) 
            {
                String alias = (String) aliases.nextElement();
                java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) ks.getCertificate(alias);

                if (cert.getIssuerDN().getName().contains(name)) 
                {
                    isCACertificateInstalled = true;
                    break;
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (java.security.cert.CertificateException e) {
        e.printStackTrace();
    }

    return isCACertificateInstalled;
}
jww
  • 97,681
  • 90
  • 411
  • 885
Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241
  • 1
    You have to be careful with *Check if a certificate is already installed*. It depends on the `{Distinguished Name, Serial Number}` pair, and not just the `Distinguished Name`. See, for example, [How to troubleshoot “Secure Connection Failed” in Firefox?](http://superuser.com/q/917887/173513) on Super User. In the question, Symantec re-issued a certificate with the same *Distinguished Name* and the same *Subject Public Key*. The only thing that differed was the serial number (and promotion from a Subordinate CA to a Self-Signed Root CA). – jww May 26 '15 at 06:33
  • 1
    @jww - we can add `cert.getSerialNumber().equals(x509.getSerialNumber())` condition along with `cert.getIssuerDN().getName().contains(name)` to check availability of particular CA. – Durai Amuthan.H May 26 '15 at 07:27
  • 1
    I think it would be appropriate to return `true` if `{DN,SN}` match. I think it would be a good idea to ***warn*** and possibly return `true` if only `{DN}` match because its probably something unexpected, like a certificate was reissued. Often, the "certificate reissued" is difficult to track down because its using rules that few people know about. For example, the obscure rule for `{DN,SN}` is in [RFC 4158, Certification Path Building](https://tools.ietf.org/rfc/rfc4158.txt). – jww May 26 '15 at 07:35
  • Oh, and believe it or not... Its `{Issuer DN, SN}` that makes a certificate unique. So maybe more correctly, its the 3-tuple `{Issuer DN, SN, Subject DN}`. That's because certificates don't exist in a vacuum - there's a relationship between the issuer and subject. Its really a mess when things go sideways. Anyway, sorry to complicate the discussion.... – jww May 26 '15 at 07:52
  • What do you think about comparing the *thumbprints* such as *MD5*,*SHA* between the two certificates ? It'd be even more precise. – Durai Amuthan.H May 26 '15 at 09:08
  • This is the grey area of "certificate equivalence" (for lack of a better term). Some bits are allowed to change. For example, imagine a certificate expires, and then is re-certified, so the only thing that effectively changes is `notBefore` and `notAfter`. Is that the same certificate for most intents and purposes? – jww May 26 '15 at 09:19
  • @jww - `{Issuer DN, SN}` would do the job. – Durai Amuthan.H May 26 '15 at 09:32
2

You cannot - android.security.KeyChain doesn't have any methods to retrieve all aliases, and more importantly - not even the service it communicates with (an implementation of the IKeyChainService AIDL interface in the KeyChain app) exposes a method to list all the aliases - thus the grants and keystore are internal to that app.

Jens
  • 16,853
  • 4
  • 55
  • 52
  • Thank you. I have another question. How I verify a given x509certificate on Android? I can use the certifcates installed on system or the certificate specific to my application. – crybird Feb 09 '12 at 06:50