带有opensc pkcs#11提供程序的java keytool仅适用于启用调试选项

我在ubuntu 11.10上使用OpenJDK运行最新的opensc 0.12.2(java版本“1.6.0_22”)

我可以阅读我的智能卡(飞天ePass PKI)

pkcs15-tool --dump 

现在我尝试使用带有keytool的智能卡:

 keytool -providerClass sun.security.pkcs11.SunPKCS11 \ -providerArg /etc/opensc/opensc-java.cfg \ -keystore NONE -storetype PKCS11 -list 

这会导致错误:

 keytool error: java.security.KeyStoreException: PKCS11 not found java.security.KeyStoreException: PKCS11 not found at java.security.KeyStore.getInstance(KeyStore.java:603) at sun.security.tools.KeyTool.doCommands(KeyTool.java:621) at sun.security.tools.KeyTool.run(KeyTool.java:194) at sun.security.tools.KeyTool.main(KeyTool.java:188) Caused by: java.security.NoSuchAlgorithmException: PKCS11 KeyStore not available at sun.security.jca.GetInstance.getInstance(GetInstance.java:159) at java.security.Security.getImpl(Security.java:696) at java.security.KeyStore.getInstance(KeyStore.java:600) ... 3 more 

当我运行相同的命令时启用调试选项,如下所示:

 keytool -providerClass sun.security.pkcs11.SunPKCS11 \ -providerArg /etc/opensc/opensc-java.cfg \ -keystore NONE -storetype PKCS11 -list \ -J-Djava.security.debug=sunpkcs11 

它突然起作用:

 ... debug infos ... Enter keystore password: sunpkcs11: login succeeded Keystore type: PKCS11 Keystore provider: SunPKCS11-OpenSC Your keystore contains 2 entries ... Certificate fingerprint (MD5): ... ... Certificate fingerprint (MD5): ... 

我静态配置时的行为相同:

 $ grep opensc /usr/lib/jvm/java-6-openjdk/jre/lib/security/java.security security.provider.7=sun.security.pkcs11.SunPKCS11 /etc/opensc/opensc-java.cfg 

和我的配置

 $ cat /etc/opensc/opensc-java.cfg name = OpenSC description = SunPKCS11 w/ OpenSC Smart card Framework library = /usr/lib/opensc-pkcs11.so 

我猜,它与openjdk或内部包sun.security ,因为它是一个内部包,所以通常不会使用它。 激活调试选项可能会激活此内部包?

我今天遇到了同样的问题,我深入研究了java源代码,直到找到了问题的根源。 我知道这个问题已经很老了,已经有了一个公认的答案,但那个问题并不是真正的答案。

基本上,SunPKCS11提供程序确实列出了所有可用的插槽,然后获取您在配置中指定的插槽,并给出错误(因为您没有指定任何插槽并且其默认值为fot)。

在调试中,列出所有可用插槽后,它会列出插入智能卡的所有插槽。 在打印了有关插槽列表的所有这些信息之后, 它会初始化其slotid变量,覆盖您在配置中写入(或忘记写入)的内容。 新值是正确的,因为它是从opensc默认值中读取的。

这是来自openjdk项目的SunPKCS11.java的相关代码:

  long slotID = config.getSlotID(); // .... if ((slotID < 0) || showInfo) { long[] slots = p11.C_GetSlotList(false); if (showInfo) { System.out.println("All slots: " + toString(slots)); slots = p11.C_GetSlotList(true); System.out.println("Slots with tokens: " + toString(slots)); } if (slotID < 0) { if ((slotListIndex < 0) || (slotListIndex >= slots.length)) { throw new ProviderException("slotListIndex is " + slotListIndex + " but token only has " + slots.length + " slots"); } slotID = slots[slotListIndex]; } } this.slotID = slotID; 

因此,一种解决方法是始终在您的配置中包含一个负值,如slot = -1 ,以便提供者始终寻找正确的值。

将调试标志添加到命令行对我有用:

 keytool -providerClass sun.security.pkcs11.SunPKCS11 \ -providerArg /home/hans/Desktop/smartcards/opensc-java.cfg \ -providerName SunPKCS11-OpenSC -keystore NONE -storetype PKCS11 \ -list \ -J-Djava.security.debug=sunpkcs11 

或者手动指定cfg文件中的插槽:

 name = OpenSC description = SunPKCS11 w/ OpenSC Smart card Framework library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so slot = 2 

我可以使用java JDK 1.6.0_20来确认这种行为

即使是简单的java程序也只适用于-Djava.security.debug = sunpkcs11 set。

 String configName = "/etc/pkcs11_java.cfg"; Provider p = new sun.security.pkcs11.SunPKCS11(configName); keyStore = KeyStore.getInstance("PKCS11", p); 

使用/etc/pkcs11_java.cfg

 name=OpenSC description = SunPKCS11 via OpenSC library=/usr/local/lib/opensc-pkcs11.so