【问题标题】:How to finalize SunPKCS11 Provider after it is initialized?SunPKCS11 Provider 初始化后如何完成?
【发布时间】:2016-10-18 12:51:09
【问题描述】:

我已通过以下方式初始化 SunPKCS11 提供程序:

Provider provider = new sun.security.pkcs11.SunPKCS11("path_to_pkcs11.cfg");
Security.addProvider(provider);

然后我使用此提供程序来初始化 KeyStore 以使用密钥进行密码操作。

KeyStore ks = KeyStore.getInstance("PKCS11", provider);
ks.load(null, "password".toCharArray());

完成密码操作后,我应该如何使用 PKCS11 令牌完成会话?

我已尝试删除提供程序,但没有成功。

Security.removeProvider("sunPCKS11ProviderName");

下次我尝试与令牌通信时,令牌会抛出此异常CKR_CRYPTOKI_ALREADY_INITIALIZED

更新

我试过了

sun.security.pkcs11.SunPKCS11.logout();

但它也不起作用。

我有一个用例,我必须同时使用 PKCS#11 Wrapper 和 Provider。为了能够使用包装器,我必须最终确定提供程序,否则当包装器尝试与令牌通信时,令牌会抛出 CKR_CRYPTOKI_ALREADY_INITIALIZED 错误。

使用代码更新:

我正在使用 Sun 的 PKCS#11 Provider 和 IAIK 的 PKCS#11 Wrapper。

public static void providerAndWrapperIssue() throws Exception
{
    final String name = "ANY_NAME";
    final String library = "LOCATION OF THE TOKENS DLL/SO";
    final String slot = "SLOT NUMBER";

    // SUN PKCS#11 Provider -------------------------------------------

    StringBuilder builder = new StringBuilder();
    builder.append("name=" + name);
    builder.append(System.getProperty("line.separator"));
    builder.append("library=\"" + library + "\"");
    builder.append(System.getProperty("line.separator"));
    builder.append("slot=" + slot);

    ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes());
    Provider provider = new sun.security.pkcs11.SunPKCS11(bais);
    Security.addProvider(provider);

    KeyStore ks = KeyStore.getInstance("PKCS11");
    ks.load(null, null);

    Enumeration<String> aliases = ks.aliases();
    while (aliases.hasMoreElements())
        System.out.println(aliases.nextElement());

    // IAIK PKCS#11 Wrapper -------------------------------------------

    Module pkcs11Module = Module.getInstance(library, false);
    pkcs11Module.initialize(null); <-- Exception here.

    Slot[] slots = pkcs11Module.getSlotList(true);

    Session session = slots[0].getToken().openSession(true, true, null, null);
    session.login(Session.UserType.USER, "".toCharArray());

    session.logout();
    session.closeSession();

    slots[0].getToken().closeAllSessions();

    pkcs11Module.finalize(null);
}

由于 Sun 的提供商没有注销并关闭会话,因此 IAIK 无法访问令牌。而且Java的Keystore api没有注销方法。

【问题讨论】:

  • 为什么要多次初始化令牌?在您的项目中创建一个单例,它将使用令牌,并在创建单例时初始化提供程序。
  • 我在单例上初始化令牌(使用提供者)。但是我有一个用例,我必须使用 PKCS#11 Wrapper 与令牌进行通信。在此初始化期间,令牌正在引发已初始化的异常。

标签: java pkcs#11 hsm


【解决方案1】:

终于找到了解决办法。 Sun 的 Provider 在下面使用 Wrapper。所以诀窍是使用 Sun 的 PKCS#11 Wrapper 来获取当前实例,并最终确定它。显然,会话功能的最终确定并未在 Provider 中公开。但是有一个解决方法,它看起来像这样:

public static void providerAndWrapperIssue() throws Exception
{
    final String name = "ANY_NAME";
    final String library = "LOCATION OF THE TOKENS DLL/SO";
    final String slot = "SLOT NUMBER";

    // SUN PKCS#11 Provider -------------------------------------------

    StringBuilder builder = new StringBuilder();
    builder.append("name=" + name);
    builder.append(System.getProperty("line.separator"));
    builder.append("library=\"" + library + "\"");
    builder.append(System.getProperty("line.separator"));
    builder.append("slot=" + slot);

    ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes());
    Provider provider = new sun.security.pkcs11.SunPKCS11(bais);
    provider.setProperty("pkcs11LibraryPath", library);
    Security.addProvider(provider);

    KeyStore ks = KeyStore.getInstance("PKCS11");
    ks.load(null, null);

    Enumeration<String> aliases = ks.aliases();
    while (aliases.hasMoreElements())
        System.out.println(aliases.nextElement());

    // ====================================
    // Solved it using the SUN PKCS#11 Wrapper

    PKCS11 pkcs11 = PKCS11.getInstance(((sun.security.pkcs11.SunPKCS11) provider).getProperty("pkcs11LibraryPath"), null, null, true);
    pkcs11.C_Finalize(PKCS11Constants.NULL_PTR);

    // ====================================

    // IAIK PKCS#11 Wrapper -------------------------------------------

    Module pkcs11Module = Module.getInstance(library, false);
    pkcs11Module.initialize(null);

    Slot[] slots = pkcs11Module.getSlotList(true);

    Session session = slots[0].getToken().openSession(true, true, null, null);
    session.login(Session.UserType.USER, "".toCharArray());

    session.logout();
    session.closeSession();

    slots[0].getToken().closeAllSessions();

    pkcs11Module.finalize(null);
}

【讨论】:

    【解决方案2】:

    你得到这个异常是因为一旦程序第一次被执行,值就会保留在 java 中的进程 ID 中。所以要解决这个问题,请将其作为 jar 文件并作为批处理文件运行

    【讨论】:

    • 在我的情况下,这不是导致问题的原因,而是通过 java KeyStore/Provider api 无法使用令牌的最终操作。这在我的业务逻辑中,所以我不能在批处理文件中使用它。
    【解决方案3】:

    导入类

    import sun.security.pkcs11.SunPKCS11;
    import sun.security.pkcs11.wrapper.PKCS11
    

    使用此方法关闭PKCSS Wrapper

        private void finalizePKCS11Wrapper(PKCS11 pkcs11) throws IOException{
        try {
            Field f = PKCS11.class.getDeclaredField("moduleMap"); 
            f.setAccessible(true);
            Map moduleMap = (Map) f.get(pkcs11);
            moduleMap.clear();
            pkcs11.C_Finalize(PKCS11Constants.NULL_PTR);
        } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException | PKCS11Exception e) {
            throw new IOException("No se pudo cerrar la sessión con el token",e);
        }
    }
    

    并关闭 sunPKCS11 连接

        public void logout() throws Exception {
        if(sunPKCS11==null)
            return;
        try {
            // Obtenemos el Wrapper del sunPKCS11
            Field f = SunPKCS11.class.getDeclaredField("p11"); 
            f.setAccessible(true);
            PKCS11 objectPKCS11 = (PKCS11)f.get(sunPKCS11);
            finalizePKCS11Wrapper(objectPKCS11);
        } catch (Exception e) {
            e.printStackTrace();
        }
        sunPKCS11.clear();
        sunPKCS11.setCallbackHandler(null);
        Security.removeProvider(sunPKCS11.getName());
        sunPKCS11 = null;
        keyStore = null;
        System.gc();
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 1970-01-01
      • 1970-01-01
      • 2019-10-05
      • 2016-01-06
      • 2015-02-17
      • 2014-10-20
      • 1970-01-01
      • 2020-06-12
      相关资源
      最近更新 更多