0

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?

Kuntal Shah
  • 183
  • 2
  • 13

2 Answers2

0

I don't like this solution, but maybe you can call deleteEntry. Load the alias you want and check if the cert is the one you want. If not, delete it. Then try to load it again. Maybe you can read them all that way. Just make sure not to call KeyStore.store. You don't want to delete the certificates in IE.

John Watts
  • 8,717
  • 1
  • 31
  • 35
  • I have tried the same thing. The problem with that is, I am not able to copy IE keystore anywhere else without using alias and if I use alias I am not able to copy the second certificate to any other keystore. Without copying it deletes the certificates from browser. – Kuntal Shah Jun 14 '12 at 00:52
0

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);
}
John Watts
  • 8,717
  • 1
  • 31
  • 35
  • I this this seems to be working forward. We are now iterating through entries. The entries are of type sun.security.mscapi.KeyStore$KeyEntry. We are not able to cast object of it as it is not visible outside mscapi package. Any further help will be much appreciated. – Kuntal Shah Jun 14 '12 at 08:26
  • You just need to do a little more reflection, as in the updated example above. – John Watts Jun 14 '12 at 13:31