Java 使用sunpkcs#11和tomcat卸下并插入智能卡

Java 使用sunpkcs#11和tomcat卸下并插入智能卡,java,tomcat,smartcard,pkcs#11,Java,Tomcat,Smartcard,Pkcs#11,我有一个运行在Tomcat上的web应用程序。我的应用程序使用一个web服务,它可以签名(通过智能卡)和发送电子邮件。web服务本身在第一次呼叫期间和发送电子邮件之前自动添加sunpkcs#11提供商,然后在未移除和插入智能卡的情况下登录并发送电子邮件。如果删除并插入,为了发送电子邮件,我必须重新启动tomcat服务器,否则它将根据我的代码给出几个错误: result= api.signAndSend(to, cc, bcc, subject, content, smartCardPin);

我有一个运行在Tomcat上的web应用程序。我的应用程序使用一个web服务,它可以签名(通过智能卡)和发送电子邮件。web服务本身在第一次呼叫期间和发送电子邮件之前自动添加
sunpkcs#11
提供商,然后在未移除和插入智能卡的情况下登录并发送电子邮件。如果删除并插入,为了发送电子邮件,我必须重新启动tomcat服务器,否则它将根据我的代码给出几个错误:

result= api.signAndSend(to, cc, bcc, subject, content, smartCardPin); 
卸下和插入智能卡后,此代码将显示以下异常消息:

令牌已被删除

以下是我的尝试:

  • 在发送电子邮件并创建一个新的
    sunpkcs#11
    提供程序并添加它之后,我尝试删除
    sunpkcs#11
    提供程序。它会出现以下错误:
  • java.security.InvalidKeyException:没有安装的提供程序支持此操作 密钥:sun.security.pkcs11.P11Key$P11PrivateKey或 java.security.InvalidKeyException:没有安装的提供程序支持此操作 键:空

  • 我没有在每次api.signAndSend(…)调用之后删除sunpkcs#11提供程序
  • 而是:

      result= api.signAndSend(to, cc, bcc, subject, content, smartCardPin);  
      SunPKCS11 sunPKCS11=(SunPKCS11)getLastProvider();  
      sunPKCS11.logout();  
      sunPKCS11.setCallbackHandler(new MyCallbackHandler());  
      KeyStore.CallbackHandlerProtection cpprotection = new KeyStore.CallbackHandlerProtection(  
      new MyCallbackHandler());  
      KeyStore.Builder builder = KeyStore.Builder.newInstance(  
      "PKCS11", sunPKCS11, cpprotection);  
      KeyStore ks = builder.getKeyStore();  
    
    //finalize PKCS#11  
    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(i expect this code to load pkcs#11 again but i am not sure)  
    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 = (PKCS11) getInstanceMethod.invoke(null, pkcs11Path,  
      "C_GetFunctionList", ck_c_initialize_args, false);  
    
    在我添加了一个新的SunPkcs11之后,当
    api.signAndSend(…)
    它给出:

    java.security.InvalidKeyException:没有安装的提供程序支持此密钥:>sun.security.pkcs11.P11Key$P11PrivateKey


    这个异常不是因为缺少SunPkcs11,因为我看到了我添加的SunPkcs11,在提供商列表中。

    很难找到此类问题的确切解决方案,因为很难重现,因此根据我的阅读,PKCS#11已经涵盖了根据其

    对于将PKCS#11令牌视为静态的应用程序来说,这很好 密钥库。对于希望容纳PKCS#11令牌的应用程序 更动态地,例如插入和移除智能卡,您可以 可以使用新的KeyStore.Builder类。下面是一个如何 使用回调处理程序初始化PKCS#11密钥库的生成器


    您已经提到,删除和添加提供程序不适用于您,但根据这一点,他们通过这种方式解决它

    请分享代码示例如何实现删除和添加提供程序的方法,根据我的阅读,这种方法应该有效。@erhun我编辑了这个问题。@IHSAN在添加提供程序(newSunPkcs11Provider)之后,您能否尝试使用名称获取它以确保成功添加它getProvider是的,我可以通过安全性获取它。getProvider(providerName).你检查过这个链接吗?
    //the code below adds sunpkcss provider automatically after first call
    result= api.signAndSend(to, cc, bcc, subject, content, smartCardPin);
    
    //after each signAndSend i remove sunpkcs and add a new one
    String sunpkcs11Name=getLastProvider().getName();
    Security.removeProvider(sunpkcs11Name);
    
    String cfg = MessageFormat.format(
                    "name = Starcos-SunPkcs11  library = c:/windows/system32/aetpkss1.dll slot = 52481 ");
            InputStream is=new ByteArrayInputStream(cfg.getBytes());
    
    SunPKCS11 newSunPkcs11Provider = new SunPKCS11(is);
    Security.addProvider(newSunPkcs11Provider);