Java 如何在SunPKCS11提供程序初始化后完成它?

Java 如何在SunPKCS11提供程序初始化后完成它?,java,pkcs#11,hsm,Java,Pkcs#11,Hsm,我已通过以下方式初始化SunPKCS11提供程序: Provider provider = new sun.security.pkcs11.SunPKCS11("path_to_pkcs11.cfg"); Security.addProvider(provider); 然后我使用这个提供程序初始化一个密钥库,以使用密钥进行密码操作 KeyStore ks = KeyStore.getInstance("PKCS11", provider); ks.load(null, "password".t

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

Provider provider = new sun.security.pkcs11.SunPKCS11("path_to_pkcs11.cfg");
Security.addProvider(provider);
然后我使用这个提供程序初始化一个密钥库,以使用密钥进行密码操作

KeyStore ks = KeyStore.getInstance("PKCS11", provider);
ks.load(null, "password".toCharArray());
完成密码操作后,如何使用PKCS11令牌完成会话?

我已尝试删除提供程序,但无效

Security.removeProvider("sunPCKS11ProviderName");
下一次尝试与令牌通信时,我从令牌CKR\u CRYPTOKI\u已初始化

更新

我试过了

sun.security.pkcs11.SunPKCS11.logout();
但它也不起作用

我有一个用例,我必须同时使用PKCS#11包装器和提供者。为了能够使用包装器,我必须完成提供程序,否则当包装器尝试与令牌通信时,令牌抛出
CKR\u CRYPTOKI\u已初始化
错误

使用代码更新:

我正在使用Sun的PKCS#11提供程序和IAIK的PKCS#11包装器

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);
}
public static void providerAndWrapperIssue()引发异常
{
final String name=“ANY_name”;
final String library=“令牌的位置DLL/SO”;
最终字符串slot=“slot NUMBER”;
//SUN PKCS#11供应商-------------------------------------------
StringBuilder=新的StringBuilder();
builder.append(“name=“+name”);
append(System.getProperty(“line.separator”);
append(“library=\”“+library+”\”);
append(System.getProperty(“line.separator”);
builder.append(“slot=“+slot”);
ByteArrayInputStream bais=新的ByteArrayInputStream(builder.toString().getBytes());
Provider Provider=new sun.security.pkcs11.SunPKCS11(BAI);
Security.addProvider(提供者);
KeyStore ks=KeyStore.getInstance(“PKCS11”);
ks.load(null,null);
枚举别名=ks.alias();
while(别名.hasMoreElements())
System.out.println(别名.nextElement());
//IAIK PKCS#11包装器-------------------------------------------
模块pkcs11Module=Module.getInstance(库,false);

pkcs11Module.initialize(null);终于找到了解决方案。Sun的提供程序使用了下面的包装器。因此,诀窍是使用Sun的PKCS#11包装器来获取当前实例,并完成它。显然,会话功能的最终完成没有在提供程序中公开。但是有一个解决方法,它看起来是这样的:

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);
}
public static void providerAndWrapperIssue()引发异常
{
final String name=“ANY_name”;
final String library=“令牌的位置DLL/SO”;
最终字符串slot=“slot NUMBER”;
//SUN PKCS#11供应商-------------------------------------------
StringBuilder=新的StringBuilder();
builder.append(“name=“+name”);
append(System.getProperty(“line.separator”);
append(“library=\”“+library+”\”);
append(System.getProperty(“line.separator”);
builder.append(“slot=“+slot”);
ByteArrayInputStream bais=新的ByteArrayInputStream(builder.toString().getBytes());
Provider Provider=new sun.security.pkcs11.SunPKCS11(BAI);
setProperty(“pkcs11LibraryPath”,library);
Security.addProvider(提供者);
KeyStore ks=KeyStore.getInstance(“PKCS11”);
ks.load(null,null);
枚举别名=ks.alias();
while(别名.hasMoreElements())
System.out.println(别名.nextElement());
// ====================================
//使用SUN PKCS#11包装器解决了此问题
PKCS11 PKCS11=PKCS11.getInstance(((sun.security.PKCS11.SunPKCS11)provider).getProperty(“pkcs11LibraryPath”),null,null,true);
pkcs11.C_Finalize(PKCS11Constants.NULL_PTR);
// ====================================
//IAIK PKCS#11包装器-------------------------------------------
模块pkcs11Module=Module.getInstance(库,false);
pkcs11Module.initialize(空);
Slot[]slots=pkcs11Module.getSlotList(true);
会话会话=插槽[0]。getToken().openSession(true,true,null,null);
session.login(session.UserType.USER,“.tocharray());
session.logout();
session.closeSession();
插槽[0]。getToken().closeAllSessions();
pkcs11Module.finalize(空);
}

您将遇到此异常,因为一旦程序第一次执行,值将保留在java中的进程id中。因此,要解决此问题,请将其作为jar文件并作为批处理文件运行

导入类

import sun.security.pkcs11.SunPKCS11;
import sun.security.pkcs11.wrapper.PKCS11
使用此方法关闭PKCSS包装器

    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();
}

为什么要多次初始化令牌?在项目中创建一个将使用令牌的单例,并在单例创建时初始化提供程序。我正在初始化令牌(使用提供程序)但我有一个使用PKCS#11包装器与令牌通信的用例。在初始化过程中,令牌抛出了已初始化的异常。在我的例子中,这并不是问题的原因,而是通过java密钥库/提供程序api无法使用令牌的终结操作。这在我的b业务逻辑,所以我不能在批处理文件中使用它。