Search code examples
javasecurityinternet-explorerx509certificatepki

Issue in Loading Internet Explorer Keystore in JAVA


I am building a cryptographic web application, which allows user to sign and encrypt on client side within browser. The application has to be compatible with IE and Firefox. It works perfectly fine in Firefox in IE I am facing one issue.

Recently, Government of India started issuing two digital certificates to individuals one for signing data and one for encryption. These certificates have same CN. I am using following code to loop through certificates.

public static Certificate selectedCert = null;
KeyStore keystore1 ;
keystore1 = KeyStore.getInstance("Windows-MY");
keystore1.load(null, null);
if (keystore1 != null) {
    enumeration = keystore1.aliases();
    while (enumeration.hasMoreElements()) {
    alias = enumeration.nextElement();
    selectedCert = keystore1.getCertificate(alias));
            System.out.println(selectedCert.getPublicKey());    
    }
}

While reading certificate from firefox keystore the alias names are generated by firefox which are unique but in case of IE, it takes certificates from IE it takes Common Name (CN) as alias. That way it gets two such entries with same alias. Now whenever I want to get the whole certificate object I have to pass alias, so whenever I pass alias it will always give me first certificate and I am unable to access the second certificate with same alias name.

To clarify more, if I have two certificates in the name of "Kuntal Shah" and one in name of "Abhishek Desai". Then the aliases enumeration will have "Kuntal Shah" "Kuntal Shah" "Abhishek Desai" when I do

selectedCert = keystore1.getCertificate(alias));

It always returns me the first one and I am never able to get the second one.

I tried some code in C#, there I have a simpler solution

X509Store storeMy = new X509Store(StoreName.My,StoreLocation.CurrentUser);
storeMy.Open(OpenFlags.ReadOnly);
Console.WriteLine("Found certs with the following subject " +"names in the {0} store:", storeMy.Name);
foreach (X509Certificate2 cert in storeMy.Certificates)
{
    Console.WriteLine("\t{0}", cert.SubjectName.Name);
}

But this does not work with firefox and it will not work on Linux.

Can any one tell me how do I access the second certificate? or is there any other different way all together?


Solution

  • This solution is even uglier than my other one, but it may actually work. You can use reflection to get direct access to the collection of all the key and certificate entries.

    public void printKeystore() {
        Field spiField = KeyStore.class.getDeclaredField("keyStoreSpi");
        spiField.setAccessible(true);
        KeyStoreSpi spi = (KeyStoreSpi) spiField.get(keystore1);
        Field entriesField = spi.getClass().getSuperclass().getDeclaredField("entries");
        entriesField.setAccessible(true);
        Collection entries = (Collection) entriesField.get(spi);
        for (Object entry : entries) {
            String alias = (String) invokeGetter(entry, "getAlias");
            Key privateKey = (Key) invokeGetter(entry, "getPrivateKey");
            X509Certificate[] certificateChain = (X509Certificate[]) invokeGetter(entry, "getCertificateChain");
            System.out.println(alias + ": " + privateKey + Arrays.toString(certificateChain));
        }
    }
    
    private Object invokeGetter(Object instance, String methodName)
            throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        Method getAlias = instance.getClass().getDeclaredMethod(methodName);
        getAlias.setAccessible(true);
        return getAlias.invoke(instance);
    }