Java Keytool只有在启用调试选项的情况下才能与OpenSC PKCS#11提供程序一起使用。

13

我在Ubuntu 11.10上运行最新的opensc 0.12.2,并使用OpenJDK (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有关,因为它是一个内部包,通常不会被使用。启用调试选项可能会激活此内部包?

3个回答

10

今天我遇到了同样的问题,于是我深入研究了Java源代码,直到找到了问题的根源。我知道这个问题已经很久了,并且已经有一个被接受的答案,但那并不是真正的答案。

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

当处于调试状态时,在列出所有可用插槽之后,它会列出所有已插入智能卡的插槽。在打印有关插槽列表的所有这些信息之后,它会初始化其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,这样提供程序就会始终查找正确的值。

1
太好了!你应该向jdk项目提交一个错误报告或补丁。 - Janning Vygen
在我的 keytool 调用中,slot = -1 技巧对我不起作用。但是,在命令行中添加 -J-Djava.security.debug=sunpkcs11 是有效的。 - Hans-Christoph Steiner
1
@Hans-ChristophSteiner,你遇到了一个不同的错误。请参见https://bugs.openjdk.java.net/browse/JDK-8039912。 - eppesuig
确认在openjdk-7-jdk:i386, 7u111-2.6.7-1中。由于我同时安装了openjdk7Oracle JDK 7,我首先检查了keytool是否链接到来自Open JDK 7的二进制文件。切换到Oracle JDK 7后问题消失了。 - WesternGun

4

在命令行中添加调试标志对我很有帮助:

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

或者在配置文件中手动指定插槽位置:
name = OpenSC
description = SunPKCS11 w/ OpenSC Smart card Framework
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
slot = 2

这个方法解决了我在OpenJDK 1.8.0_144中的问题。 - rhoerbe

3
我可以确认使用Java JDK 1.6.0_20会出现这种行为。
甚至一个简单的Java程序,只有在设置了-Djava.security.debug=sunpkcs11时才能正常工作。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接