使用多个读卡器加载 PKCS 密钥库时出错
Posted
技术标签:
【中文标题】使用多个读卡器加载 PKCS 密钥库时出错【英文标题】:Error loading PKCS keystore with multiple card readers 【发布时间】:2020-03-20 18:15:04 【问题描述】:在多终端设置中,从第 N 个(除了第一个)终端读取 CAC 卡时,我遇到了一个奇怪的问题。
环境 - JDK8_u211,无需任何读卡器的Destop,笔记本电脑内置读卡器,USB读卡器,CAC\PIV卡
用例尝试
-
当 CAC 卡插入 笔记本电脑的内部插槽时,无论是否连接到笔记本电脑的 USB 卡终端,一切正常。
将 CAC 卡插入 USB 读卡器并连接到 桌面 后,一切正常。
当 CAC 卡插入 USB 读卡器并连接到 笔记本电脑 时,PKCS 存储实例化失败,因为配置使用 slot=1
当 CAC 卡插入 USB 读卡器并连接到 笔记本电脑,如果我在配置中硬编码 slot=4,一切正常。李>
问题:无法确定要在配置文件中使用的正确插槽。不知何故,终端数量没有加起来以确定运行时的插槽。
通过启用 JDK 调试日志,我可以在内部验证 "C_GetSlotList" 返回 0,4,因为我只有 2 个终端,因此使用索引 0 或 1。
有谁知道如何确定终端与插槽之间的相关性,或者我尝试读卡的方式真的有问题吗?
请指教。
示例代码
public class MultipleTerminals
private static String DLL_PATH = "C:\\opensc-pkcs11.dll";
public static void main(String[] args) throws Exception
MyTerminal custTerminalObj = getSmartCardTerminal();
CardTerminal terminal = custTerminalObj.getTerminal();
Integer terminalIdx = custTerminalObj.getIndex();
System.out.println("Using Terminal.Name: " + terminal.getName());
System.out.println("Using Terminal.isCardPresent: " + ((CardTerminal)terminal).isCardPresent());
if (terminal.isCardPresent()) // duplicate check
registerProvider(4);
KeyStore keyStore = createKeyStore();
printCertificate(keyStore);
public static MyTerminal getSmartCardTerminal()
System.out.println("---------------------------------------------------");
MyTerminal terminal = null;
int terminalIdx = -1;
try
TerminalFactory factory = TerminalFactory.getDefault();
if (factory != null)
List<CardTerminal> allTerminals = factory.terminals().list();
for(CardTerminal term : allTerminals)
System.out.println("Terminal Name: " + term.getName());
System.out.println("isCardPresent: " + term.isCardPresent());
System.out.println("----------");
for(CardTerminal term : allTerminals)
terminalIdx++;
if(term.isCardPresent())
terminal = new MyTerminal();
terminal.setIndex(terminalIdx);
terminal.setTerminal(term);
System.out.println("Using Terminal Idx: " + terminalIdx);
catch (CardException e1)
terminal = null;
System.out.println("SmartCardHelper.getSmartCardTerminal --> "
+ "Exception while accessing smart-card terminal: "
+ e1.getMessage());
e1.printStackTrace();
return terminal;
public static void registerProvider(Integer idx)
System.out.println("---------------------------------------------------");
String ext = "attributes(*,*,*)=\n\nCKA_TOKEN=true\nCKA_LOCAL=true\n";
String OPENSC_DEFAULT_PROVIDER_NAME = "PKCS#11";
String OPENSC_PKCS11_DLL = DLL_PATH;
String configString = "name = "
+ OPENSC_DEFAULT_PROVIDER_NAME.replace(' ', '_') + "\n"
+ "library = "
+ OPENSC_PKCS11_DLL + "\n slot = " + idx + " "
+ "\n attributes = compatibility \n" + ext;
System.out.println("\tConfigString: " + configString);
ByteArrayInputStream is = new ByteArrayInputStream(
configString.getBytes(Charset.defaultCharset()));
Provider cardSecurityProvider = new sun.security.pkcs11.SunPKCS11(
is);
displayProviders();
Security.addProvider(cardSecurityProvider);
displayProviders();
System.out.println("==================");
public static KeyStore createKeyStore() throws KeyStoreException
KeyStore.CallbackHandlerProtection callbackHandler = new KeyStore.CallbackHandlerProtection(
new PIVCardPinHandler());
KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", null,
callbackHandler);
return builder.getKeyStore();
public static void displayProviders()
System.out.println("---------------------------------------------------");
Provider[] objs = Security.getProviders();
System.out.println("Provider Count: " + objs.length);
String type = "KeyStore";
String algorithm="PKCS11";
ProviderList list = Providers.getProviderList();
Provider provider = list.getProvider("SunPKCS11-PKCS");
System.out.println("Provider[SunPKCS11-PKCS]: " + provider);
if(provider != null)
Set<Service> svcs = provider.getServices();
System.out.println("Service count: " + svcs.size());
Service firstService = list.getService(type, algorithm);
System.out.println("Type[KeyStore], Algo[PKCS11], Service: " + firstService);
public static void printCertificate(KeyStore keyStore)
throws KeyStoreException
for (String alias : Collections.list(keyStore.aliases()))
System.out.println("Alias: " + alias);
class MyTerminal
private Integer index;
private CardTerminal terminal;
public MyTerminal()
public Integer getIndex()
return index;
public void setIndex(Integer index)
this.index = index;
public CardTerminal getTerminal()
return terminal;
public void setTerminal(CardTerminal terminal)
this.terminal = terminal;
* 输出 TestCase-1 (WORKING)*
---------------------------------------------------
Terminal Name: Alcor Micro USB Smart Card Reader 0
isCardPresent: true
----------
Terminal Name: Identive SCR33xx v2.0 USB SC Reader 0
isCardPresent: false
----------
Using Terminal Idx: 0
Using Terminal.Name: Alcor Micro USB Smart Card Reader 0
Using Terminal.isCardPresent: true
---------------------------------------------------
ConfigString:
name = PKCS#11
library = C:\opensc-pkcs11.dll
slot = 0
attributes = compatibility
attributes(*,*,*)=
CKA_TOKEN=true
CKA_LOCAL=true
SunPKCS11 loading ---DummyConfig-1---
sunpkcs11: Initializing PKCS#11 library C:\opensc-pkcs11.dll
Information for provider SunPKCS11-PKCS
Library info:
cryptokiVersion: 2.20
manufacturerID: DUMMY_VALUE
flags: 0
libraryDescription: DUMMY_VALUE
libraryVersion: 0.19
All slots: 0, 4
Slots with tokens: 0, 4
Slot info for slot 0:
slotDescription: Alcor Micro USB Smart Card Reader 0
manufacturerID: DUMMY_VALUE
flags: CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE | CKF_HW_SLOT
hardwareVersion: 0.00
firmwareVersion: 0.00
Token info for token in slot 0:
label: DUMMY_VALUE
manufacturerID: DUMMY_VALUE
model: PKCS#15 emulated
serialNumber: DUMMY_VALUE
flags: CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED
ulMaxSessionCount: CK_EFFECTIVELY_INFINITE
ulSessionCount: 0
ulMaxRwSessionCount: CK_EFFECTIVELY_INFINITE
ulRwSessionCount: 0
ulMaxPinLen: 8
ulMinPinLen: 4
ulTotalPublicMemory: CK_UNAVAILABLE_INFORMATION
ulFreePublicMemory: CK_UNAVAILABLE_INFORMATION
ulTotalPrivateMemory: CK_UNAVAILABLE_INFORMATION
ulFreePrivateMemory: CK_UNAVAILABLE_INFORMATION
hardwareVersion: 0.00
firmwareVersion: 0.00
utcTime:
---------------------------------------------------
Provider Count: 10
Provider[SunPKCS11-PKCS]: null
Type[KeyStore], Algo[PKCS11], Service: null
---------------------------------------------------
Provider Count: 11
Provider[SunPKCS11-PKCS]: SunPKCS11-PKCS version 1.8
Service count: 26
Type[KeyStore], Algo[PKCS11], Service: SunPKCS11-PKCS: KeyStore.PKCS11 -> sun.security.pkcs11.P11KeyStore
aliases: [PKCS11-PKCS]
(KeyStore)
==================
sunpkcs11: caller passed NULL pin
* 输出 TestCase-3(不工作)*
---------------------------------------------------
Terminal Name: Alcor Micro USB Smart Card Reader 0
isCardPresent: false
----------
Terminal Name: Identive SCR33xx v2.0 USB SC Reader 0
isCardPresent: true
----------
Using Terminal Idx: 1
Using Terminal.Name: Identive SCR33xx v2.0 USB SC Reader 0
Using Terminal.isCardPresent: true
---------------------------------------------------
ConfigString:
name = PKCS#11
library = C:\opensc-pkcs11.dll
slot = 1
attributes = compatibility
attributes(*,*,*)=
CKA_TOKEN=true
CKA_LOCAL=true
SunPKCS11 loading ---DummyConfig-1---
sunpkcs11: Initializing PKCS#11 library C:\opensc-pkcs11.dll
Information for provider SunPKCS11-PKCS
Library info:
cryptokiVersion: 2.20
manufacturerID: DUMMY_VALUE
flags: 0
libraryDescription: DUMMY_VALUE
libraryVersion: 0.19
All slots: 0, 4
Slots with tokens: 0, 4
---------------------------------------------------
Provider Count: 10
Provider[SunPKCS11-PKCS]: null
Type[KeyStore], Algo[PKCS11], Service: null
---------------------------------------------------
Provider Count: 11
Provider[SunPKCS11-PKCS]: SunPKCS11-PKCS version 1.8
Service count: 0
Type[KeyStore], Algo[PKCS11], Service: null
==================
Exception in thread "main" java.security.KeyStoreException: KeyStore instantiation failed
at java.security.KeyStore$Builder$2.getKeyStore(KeyStore.java:1967)
Caused by: java.security.KeyStoreException: PKCS11 not found
at java.security.KeyStore.getInstance(KeyStore.java:851)
at java.security.KeyStore$Builder$2$1.run(KeyStore.java:1923)
at java.security.KeyStore$Builder$2$1.run(KeyStore.java:1918)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.KeyStore$Builder$2.getKeyStore(KeyStore.java:1964)
... 2 more
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:695)
at java.security.KeyStore.getInstance(KeyStore.java:848)
... 6 more
* 输出 TestCase-4 (WORKING)*
---------------------------------------------------
Terminal Name: Alcor Micro USB Smart Card Reader 0
isCardPresent: false
----------
Terminal Name: Identive SCR33xx v2.0 USB SC Reader 0
isCardPresent: true
----------
Using Terminal Idx: 1
Using Terminal.Name: Identive SCR33xx v2.0 USB SC Reader 0
Using Terminal.isCardPresent: true
---------------------------------------------------
ConfigString:
name = PKCS#11
library = C:\opensc-pkcs11.dll
slot = 4
attributes = compatibility
attributes(*,*,*)=
CKA_TOKEN=true
CKA_LOCAL=true
SunPKCS11 loading ---DummyConfig-1---
sunpkcs11: Initializing PKCS#11 library C:\opensc-pkcs11.dll
Information for provider SunPKCS11-PKCS
Library info:
cryptokiVersion: DUMMY_VALUE
manufacturerID: DUMMY_VALUE
flags: 0
libraryDescription: DUMMY_VALUE
libraryVersion: DUMMY_VALUE
All slots: 0, 4
Slots with tokens: 0, 4
Slot info for slot 4:
slotDescription: DUMMY_VALUE
manufacturerID: DUMMY_VALUE
flags: CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE | CKF_HW_SLOT
hardwareVersion: 0.00
firmwareVersion: 0.00
Token info for token in slot 4:
label: DUMMY_LABEL
manufacturerID: DUMMY_VALUE
model: PKCS#15 emulated
serialNumber: DUMMY_VALUE
flags: CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED
ulMaxSessionCount: CK_EFFECTIVELY_INFINITE
ulSessionCount: 0
ulMaxRwSessionCount: CK_EFFECTIVELY_INFINITE
ulRwSessionCount: 0
ulMaxPinLen: 8
ulMinPinLen: 4
ulTotalPublicMemory: CK_UNAVAILABLE_INFORMATION
ulFreePublicMemory: CK_UNAVAILABLE_INFORMATION
ulTotalPrivateMemory: CK_UNAVAILABLE_INFORMATION
ulFreePrivateMemory: CK_UNAVAILABLE_INFORMATION
hardwareVersion: 0.00
firmwareVersion: 0.00
utcTime:
---------------------------------------------------
Provider Count: 10
Provider[SunPKCS11-PKCS]: null
Type[KeyStore], Algo[PKCS11], Service: null
---------------------------------------------------
Provider Count: 11
Provider[SunPKCS11-PKCS]: SunPKCS11-PKCS version 1.8
Service count: 26
Type[KeyStore], Algo[PKCS11], Service: SunPKCS11-PKCS: KeyStore.PKCS11 -> sun.security.pkcs11.P11KeyStore
aliases: [PKCS11-PKCS]
(KeyStore)
==================
sunpkcs11: caller passed NULL pin
【问题讨论】:
【参考方案1】:您对 slot id 和 slot index 感到困惑。它们是两个不同的属性。
C_GetSlotList
为您提供slot id's
的数组,而不是插槽索引。在您的情况下,0
和 4
是插槽 ID,而不是插槽索引。 slot index是slot id在数组中的索引。
在您识别terminalIdx
的getSmartCardTerminal()
方法中,您正在识别索引,但在您的registerProvider(Integer idx)
方法中,您将索引映射为id,在这里:
OPENSC_PKCS11_DLL + "\n 插槽 = " + idx + " "
当你使用槽索引时,你应该使用slotListIndex
,当你使用槽ID时,你应该使用slot
。
所以要解决您的问题,请将其更改为:
OPENSC_PKCS11_DLL + "\n slotListIndex = " + idx + " "
文档here。
【讨论】:
在进行了“always_a_rookie_to_learn”推荐的更改后,一切正常。 现在我已经将 OpenSC 版本从 19 更新到 20,我看到 PKCS 初始化错误由于索引...基于 PKCS 日志似乎是 v20 中修复的 DLL 问题所有插槽:0 , 4 个带令牌的插槽:线程“主”java.security.ProviderException 中的 4 个异常:在 registerProvider(MultipleTerminals.java:115) 处初始化失败 原因:java.security.ProviderException:slotListIndex 为 1,但令牌在 sun 处只有 1 个插槽.security.pkcs11.SunPKCS11.以上是关于使用多个读卡器加载 PKCS 密钥库时出错的主要内容,如果未能解决你的问题,请参考以下文章