2012-06-13 23 views
0

我正在构建一个加密的Web应用程序,它允许用户在浏览器内的客户端进行签名和加密。该应用程序必须与IE和Firefox兼容。它在IE浏览器中的Firefox中工作得很好,我面临着一个问题。加载JAVA中的Internet Explorer密钥存储区中的问题

最近,印度政府开始向个人签发两个数字证书,一个用于签署数据,另一个用于加密。这些证书具有相同的CN。我正在使用以下代码来循环证书。

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());  
    } 
} 

虽然从Firefox读取证书密钥库中的别名由火狐其是唯一的,但是在IE的情况下,它需要从IE需要通用名称(CN)作为别名证书生成的。这样它会得到两个具有相同别名的条目。现在,无论何时我想要获取整个证书对象,都必须传递别名,所以无论何时传递别名,它总是会给我第一个证书,而我无法访问具有相同别名的第二个证书。

要澄清更多,如果我有两个以“Kuntal Shah”名义和一个名为“Abhishek Desai”的证书。 然后别名枚举将有 “Kuntal沙阿” “Kuntal沙阿” “阿布舍克德赛” 当我做

selectedCert = keystore1.getCertificate(alias)); 

它总是返回我的第一个,我从来没有能够得到第二个。

我尝试了一些代码,在C#中,我有一个简单的解决方案

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); 
} 

但是,这并不与Firefox,并且它不会在Linux上运行。

任何人都可以告诉我如何访问第二个证书吗?或者还有其他不同的方式吗?

+0

谢谢@GregKopff,我会按照解释的那样做。 –

回答

0

这个解决方案比我的其他解决方案更丑,但实际上它可能工作。您可以使用反射来直接访问所有密钥和证书条目的集合。

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); 
} 
+0

我这似乎在努力。我们现在正在迭代条目。这些条目的类型为sun.security.mscapi.KeyStore $ KeyEntry。我们无法投射它的对象,因为它在mscapi包之外是不可见的。任何进一步的帮助将不胜感激。 –

+0

你只需要做更多的思考,就像上面更新的例子。 –

+0

感谢它完美的工作。 –

0

我不喜欢这个解决方案,但也许你可以调用deleteEntry。加载你想要的别名,并检查证书是否是你想要的。如果没有,请删除它。然后尝试再次加载它。也许你可以一路阅读。只要确保不要调用KeyStore.store。您不想删除IE中的证书。

+0

我试过同样的事情。这样做的问题是,我无法在其他地方复制IE密钥库而不使用别名,如果使用别名,我无法将第二个证书复制到任何其他密钥库。不复制它将从浏览器中删除证书。 –