The android.security.KeyChain#getCertificateChain needs an alias. But I want to get all installed X509Certificate.
Asked
Active
Viewed 3,933 times
3 Answers
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
-
1You 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
-
1I 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