背景信息这可能有助于 alaysis :
我正在尝试从 Web 应用程序连接到智能卡并从运行在客户端计算机上的 java 程序读取证书以执行一些签名操作。我正在使用 Opensc-PKCS11.dll 和 java sunpkcs11 提供程序类来访问智能卡上的证书(FIPS PIV 合规智能卡)。
我的问题是只要连接了智能卡,我就可以访问智能卡上的密钥库并执行加密操作,但是当我们移除智能卡并再次插入时,程序无法获取插槽 ID,因为加载提供程序失败。
由于我无法硬编码我的插槽 ID,因此我将其保留为 0/-1
Config file content
Name="Opensc"
Library="OpenSC-PKCS11.dll"
slot=-1
showinfo=true
byte[] pkcs11configBytes = configName.getBytes();
ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11configBytes);
bc = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(bc);
sun = new sun.security.pkcs11.SunPKCS11(confStream);
Security.addProvider(sun);
尽管相关,但这个问题确实提供了足够的信息。 Java - 如何检测智能卡热插拔
更新:我可以解决这个问题。在 finally 块中,我在提供者的工作完成后从提供者调用了 C_Finalize。对于在同一个 java 实例中的下一次运行,我做了一些类似下面清除 PKCS11 映射并再次初始化提供程序的事情
Field moduleMapField = PKCS11.class.getDeclaredField("moduleMap");
moduleMapField.setAccessible(true);
Map<?, ?> moduleMap = (Map<?, ?>) moduleMapField.get(null);
moduleMap.clear(); // force re-execution of C_Initialize next time
//load PKCS#11
Method getInstanceMethod = PKCS11.class.getMethod("getInstance",
String.class, String.class, CK_C_INITIALIZE_ARGS.class,
Boolean.TYPE);
CK_C_INITIALIZE_ARGS ck_c_initialize_args = new CK_C_INITIALIZE_ARGS();
pkcs11 = (PKCS11) getInstanceMethod.invoke(null, libFile,
"C_GetFunctionList", ck_c_initialize_args, false);