Pkcs11Exception:方法 C_Initialize 返回 2147483907

Pkcs11Exception: Method C_Initialize returned 2147483907

我有一个使用 Pkcs11Interop 访问我的 HSM 的简单方法。

这是函数:

static public byte[] findTargetKeySValue(String label, String type, string command)
{
    try
    {
        string pkcs11LibraryPath = @"C:\Program Files\SafeNet\Protect Toolkit 5\Protect Toolkit C SDK\bin\hsm\cryptoki.dll";
        Utility.Logger("cryptoki dll path " + pkcs11LibraryPath, command);
        using (Pkcs11 pkcs11 = new Pkcs11(pkcs11LibraryPath, Inter_Settings.AppType))
        {
            // Find first slot with token present
            Slot slot = Inter_Helpers.GetUsableSlot(pkcs11);
            // Open RW session
            using (Session session = slot.OpenSession(SessionType.ReadOnly))
            {
                // Login as normal user
                session.Login(CKU.CKU_USER, Inter_Settings.NormalUserPin);
                // Prepare attribute template that defines search criteria
                List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>();
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                if (type == "DES")
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES));
                else if (type == "DES2")
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES2));
                else if (type == "DES3")
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, label));//PROVAK

                List<ObjectHandle> foundObjects = session.FindAllObjects(objectAttributes);
                var key = foundObjects[0];
                byte[] plainKeyValue = null;
                List<ObjectAttribute> readAttrsSensitive = session.GetAttributeValue(key, new List<CKA>() { CKA.CKA_SENSITIVE });
                if (!readAttrsSensitive[0].GetValueAsBool())
                {
                    Utility.Logger("findTargetKeySValue chiave " + label + " non senstive", command);
                    List<ObjectAttribute> readAttrs = session.GetAttributeValue(key, new List<CKA>() { CKA.CKA_VALUE });
                    if (readAttrs[0].CannotBeRead)
                        throw new Exception("Key cannot be exported");
                    else
                        plainKeyValue = readAttrs[0].GetValueAsByteArray();
                    //Console.WriteLine(ByteArrayToAsciiHEX(plainKeyValue));
                    session.Logout();
                    return plainKeyValue;
                }
                else
                {
                    Utility.Logger("findTargetKeySValue chiave " + label + " senstive", command);
                    Console.WriteLine("wrap/unwrap");
                    objectAttributes = new List<ObjectAttribute>();
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, "WRAPPING_KEY")); //WRAPPING_KEY WRK
                    foundObjects = session.FindAllObjects(objectAttributes);

                    var wrappingKey = foundObjects[0];
                    Mechanism m = new Mechanism(CKM.CKM_DES3_ECB);

                    var wrapped = session.WrapKey(m, wrappingKey, key);
                    //Console.WriteLine("wrapped " + ByteArrayToAsciiHEX(wrapped));

                    //Console.WriteLine(ByteArrayToAsciiHEX(session.Decrypt(m, wrappingKey, wrapped)));
                    var k = session.Decrypt(m, wrappingKey, wrapped); 
                    session.Logout();
                    return k;

                }
            }
        }
    }
    catch (Exception e)
    {
        //Console.WriteLine(e.ToSafeString());
        Utility.Logger("findTargetKeySValue " + e.ToSafeString(), command);
        return null;
    }
}

当套接字服务器收到来自客户端的调用时,我在套接字服务器中调用了这个方法。

为了测试它,我创建了一个带循环的小程序。在此循环中,它每秒向服务器发送大约 3 个请求,这些请求使用 Pkcs11Interop。

让我们称这个测试程序为tester.exe。如果我运行tester.exe,似乎一切正常。但是,虽然第一个 tester.exe 是 运行ning,但我尝试执行 tester.exe 的另一个实例时,我得到了错误

Net.Pkcs11Interop.Common.Pkcs11Exception: Method C_Initialize returned 2147483907

在此特定行代码中:

using (Pkcs11 pkcs11 = new Pkcs11(pkcs11LibraryPath, Inter_Settings.AppType))

为什么?问题出在哪里?

更新:

AppType 是

public static AppType AppType = AppType.MultiThreaded;

初始设置为:

static Inter_Settings()
{

    if (AppType == AppType.MultiThreaded)
    {
        InitArgs40 = new LLA40.CK_C_INITIALIZE_ARGS();
        InitArgs40.Flags = CKF.CKF_OS_LOCKING_OK;

        InitArgs41 = new LLA41.CK_C_INITIALIZE_ARGS();
        InitArgs41.Flags = CKF.CKF_OS_LOCKING_OK;

        InitArgs80 = new LLA80.CK_C_INITIALIZE_ARGS();
        InitArgs80.Flags = CKF.CKF_OS_LOCKING_OK;

        InitArgs81 = new LLA81.CK_C_INITIALIZE_ARGS();
        InitArgs81.Flags = CKF.CKF_OS_LOCKING_OK;
    }

    // Convert strings to byte arrays
    SecurityOfficerPinArray = ConvertUtils.Utf8StringToBytes(SecurityOfficerPin);
    NormalUserPinArray = ConvertUtils.Utf8StringToBytes(NormalUserPin);
    ApplicationNameArray = ConvertUtils.Utf8StringToBytes(ApplicationName);

    // Build PKCS#11 URI that identifies private key usable in signature creation tests
    Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
    pkcs11UriBuilder.ModulePath = Pkcs11LibraryPath;
    pkcs11UriBuilder.Serial = TokenSerial;
    pkcs11UriBuilder.Token = TokenLabel;
    pkcs11UriBuilder.PinValue = NormalUserPin;
    pkcs11UriBuilder.Type = CKO.CKO_PRIVATE_KEY;
    pkcs11UriBuilder.Object = ApplicationName;

    PrivateKeyUri = pkcs11UriBuilder.ToString();
}

更新2:

public class InteropHSM
{
    private Pkcs11 _pkcs11 = null;
    private Slot _slot = null;

    public InteropHSM()
    {
        string pkcs11LibraryPath = @"C:\Program Files\SafeNet\Protect Toolkit 5\Protect Toolkit C SDK\bin\hsm\cryptoki.dll";
        _pkcs11 = new Pkcs11(pkcs11LibraryPath, Inter_Settings.AppType);
        _slot = Inter_Helpers.GetUsableSlot(_pkcs11);
    }

    public byte[] findTargetKeySValue(String label, String type, string command)
    {

        try
        {
            //string pkcs11LibraryPath = @"C:\Program Files\SafeNet\Protect Toolkit 5\Protect Toolkit C SDK\bin\hsm\cryptoki.dll";
            //Utility.Logger("cryptoki dll path " + pkcs11LibraryPath, command);
            //using (Pkcs11 pkcs11 = new Pkcs11(pkcs11LibraryPath, Inter_Settings.AppType))
            //{

                //Slot slot = Inter_Helpers.GetUsableSlot(_pkcs11);

                using (Session session = _slot.OpenSession(SessionType.ReadOnly))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Inter_Settings.NormalUserPin);
                    // Prepare attribute template that defines search criteria
                    List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>();
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                    if (type == "DES")
                        objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES));
                    else if (type == "DES2")
                        objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES2));
                    else if (type == "DES3")
                        objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, label));//PROVAK

                    List<ObjectHandle> foundObjects = session.FindAllObjects(objectAttributes);
                    var key = foundObjects[0];
                    byte[] plainKeyValue = null;
                    List<ObjectAttribute> readAttrsSensitive = session.GetAttributeValue(key, new List<CKA>() { CKA.CKA_SENSITIVE });
                    if (!readAttrsSensitive[0].GetValueAsBool())
                    {
                        Utility.Logger("findTargetKeySValue chiave " + label + " non senstive", command);
                        List<ObjectAttribute> readAttrs = session.GetAttributeValue(key, new List<CKA>() { CKA.CKA_VALUE });
                        if (readAttrs[0].CannotBeRead)
                            throw new Exception("Key cannot be exported");
                        else
                            plainKeyValue = readAttrs[0].GetValueAsByteArray();
                        //Console.WriteLine(ByteArrayToAsciiHEX(plainKeyValue));
                        session.Logout();
                        return plainKeyValue;
                    }
                    else
                    {
                        Utility.Logger("findTargetKeySValue chiave " + label + " senstive", command);
                        Console.WriteLine("wrap/unwrap");
                        objectAttributes = new List<ObjectAttribute>();
                        objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                        objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                        objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, "WRAPPING_KEY")); //WRAPPING_KEY WRK
                        foundObjects = session.FindAllObjects(objectAttributes);

                        var wrappingKey = foundObjects[0];
                        Mechanism m = new Mechanism(CKM.CKM_DES3_ECB);

                        var wrapped = session.WrapKey(m, wrappingKey, key);
                        //Console.WriteLine("wrapped " + ByteArrayToAsciiHEX(wrapped));

                        Console.WriteLine(ByteArrayToAsciiHEX(session.Decrypt(m, wrappingKey, wrapped)));
                        var k = session.Decrypt(m, wrappingKey, wrapped); 
                        session.Logout();
                        return k;

                    }
                }
            //}
        }
        catch (Exception e)
        {
            //Console.WriteLine(e.ToSafeString());
            Utility.Logger("findTargetKeySValue " + e.ToSafeString(), command);
            return null;
        }
    }
    public static string ByteArrayToAsciiHEX(byte[] ba)
    {
        string hex = BitConverter.ToString(ba);
        return hex.Replace("-", "");
    }
}

每次调用时,服务器实例都会调用class上面的方法findTargetKeySValue。如果服务器收到并发请求,则 HSM 交互失败......但我越来越疯狂,会话每次都不一样,就像规范说的那样。

更新3

Thread t = new Thread(() => ih.findTargetKeySValue(label, type, command));
t.Start();
Thread tt = new Thread(() => ih.findTargetKeySValue(label, type, command));
tt.Start();
Thread ttt = new Thread(() => ih.findTargetKeySValue(label, type, command));
ttt.Start();
Thread tttt = new Thread(() => ih.findTargetKeySValue(label, type, command));
tttt.Start();
Thread ttttt = new Thread(() => ih.findTargetKeySValue(label, type, command));
ttttt.Start();

我创建了这个简单的片段来测试多线程(上面定义了 findTargetKeySValue),它崩溃并显示消息 "Method C_Initialize returned 2147483907"。此代码由供应商定义,并且是 CKR_CRYPTOKI_UNUSABLE。我将在接下来的测试中使用它。

更新4:

我更改了

中的代码
public InteropHSM()
{
    string pkcs11LibraryPath = @"C:\Program Files\SafeNet\Protect Toolkit 5\Protect Toolkit C SDK\bin\hsm\cryptoki.dll";
    _pkcs11 = new Pkcs11(pkcs11LibraryPath, Inter_Settings.AppType);
    _slot = Inter_Helpers.GetUsableSlot(_pkcs11);
    session = _slot.OpenSession(SessionType.ReadOnly);
    session.Login(CKU.CKU_USER, Inter_Settings.NormalUserPin);
}

public byte[] findTargetKeySValue(String label, String type, string command)
{

    try
    {
            List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>();
            objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
            if (type == "DES")
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES));
            else if (type == "DES2")
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES2));
            else if (type == "DES3")
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
            objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, label));//PROVAK

            List<ObjectHandle> foundObjects = session.FindAllObjects(objectAttributes);
            var key = foundObjects[0];
            byte[] plainKeyValue = null;
            List<ObjectAttribute> readAttrsSensitive = session.GetAttributeValue(key, new List<CKA>() { CKA.CKA_SENSITIVE });
            if (!readAttrsSensitive[0].GetValueAsBool())
            {
                Utility.Logger("findTargetKeySValue chiave " + label + " non senstive", command);
                List<ObjectAttribute> readAttrs = session.GetAttributeValue(key, new List<CKA>() { CKA.CKA_VALUE });
                if (readAttrs[0].CannotBeRead)
                    throw new Exception("Key cannot be exported");
                else
                    plainKeyValue = readAttrs[0].GetValueAsByteArray();
                //Console.WriteLine(ByteArrayToAsciiHEX(plainKeyValue));
                session.Logout();
            Console.WriteLine(plainKeyValue);
            return plainKeyValue;
            }
            else
            {
                Utility.Logger("findTargetKeySValue chiave " + label + " senstive", command);
                Console.WriteLine("wrap/unwrap");
                objectAttributes = new List<ObjectAttribute>();
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, "WRAPPING_KEY")); //WRAPPING_KEY WRK
                foundObjects = session.FindAllObjects(objectAttributes);

                var wrappingKey = foundObjects[0];
                Mechanism m = new Mechanism(CKM.CKM_DES3_ECB);

                var wrapped = session.WrapKey(m, wrappingKey, key);
                //Console.WriteLine("wrapped " + ByteArrayToAsciiHEX(wrapped));

                Console.WriteLine(ByteArrayToAsciiHEX(session.Decrypt(m, wrappingKey, wrapped)));
                var k = session.Decrypt(m, wrappingKey, wrapped);
                //session.Logout();
                return k;

        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToSafeString());
        Utility.Logger("findTargetKeySValue " + e.ToSafeString(), command);
        return null;
    }
}

我用 UPDATE3 中的代码调用它。当代码调用

时,我得到 方法 C_FindObjectsFinal 返回 CKR_OPERATION_NOT_INITIALIZED
List<ObjectHandle> foundObjects = session.FindAllObjects(objectAttributes);

您没有在多线程应用程序中正确使用 PKCS#11 API。这是一个known issue.

简短的回答是您需要确保:

  • 您正在您的应用程序中使用 Pkcs11 class 的单个实例(即在服务器启动期间加载并在其停止期间卸载)
  • 您正在为每个加密操作使用 Session class 的新实例

长答案是您需要阅读 PKCS#11 v2.20 specification which explains all basic concepts of PKCS#11 API. After you finish this mandatory reading, you can take a look at Pkcs11RsaSignature class in Pkcs11Interop.PDF 项目的 "Chapter 6 - General overview" 以获得可以使用的 class 的工作代码示例在多线程环境中。

这是修复示例 4 中的代码的方法:

public InteropHSM()
{
    string pkcs11LibraryPath = @"C:\Program Files\SafeNet\Protect Toolkit 5\Protect Toolkit C SDK\bin\hsm\cryptoki.dll";
    _pkcs11 = new Pkcs11(pkcs11LibraryPath, Inter_Settings.AppType);
    _slot = Inter_Helpers.GetUsableSlot(_pkcs11);
    session = _slot.OpenSession(SessionType.ReadOnly);
    session.Login(CKU.CKU_USER, Inter_Settings.NormalUserPin);
}

public byte[] findTargetKeySValue(String label, String type, string command)
{
    try
    {
        List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>();
        objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
        if (type == "DES")
            objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES));
        else if (type == "DES2")
            objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES2));
        else if (type == "DES3")
            objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
        objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, label));//PROVAK

        using (var session2 = _slot.OpenSession(SessionType.ReadOnly))
        {
            List<ObjectHandle> foundObjects = session2.FindAllObjects(objectAttributes);
            var key = foundObjects[0];
            byte[] plainKeyValue = null;
            List<ObjectAttribute> readAttrsSensitive = session2.GetAttributeValue(key, new List<CKA>() { CKA.CKA_SENSITIVE });
            if (!readAttrsSensitive[0].GetValueAsBool())
            {
                Utility.Logger("findTargetKeySValue chiave " + label + " non senstive", command);
                List<ObjectAttribute> readAttrs = session2.GetAttributeValue(key, new List<CKA>() { CKA.CKA_VALUE });
                if (readAttrs[0].CannotBeRead)
                    throw new Exception("Key cannot be exported");
                else
                    plainKeyValue = readAttrs[0].GetValueAsByteArray();
                Console.WriteLine(plainKeyValue);
                return plainKeyValue;
            }
            else
            {
                Utility.Logger("findTargetKeySValue chiave " + label + " senstive", command);
                Console.WriteLine("wrap/unwrap");
                objectAttributes = new List<ObjectAttribute>();
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, "WRAPPING_KEY")); //WRAPPING_KEY WRK
                foundObjects = session2.FindAllObjects(objectAttributes);

                var wrappingKey = foundObjects[0];
                Mechanism m = new Mechanism(CKM.CKM_DES3_ECB);

                var wrapped = session2.WrapKey(m, wrappingKey, key);
                //Console.WriteLine("wrapped " + ByteArrayToAsciiHEX(wrapped));

                Console.WriteLine(ByteArrayToAsciiHEX(session2.Decrypt(m, wrappingKey, wrapped)));
                var k = session2.Decrypt(m, wrappingKey, wrapped);
                return k;
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToSafeString());
        Utility.Logger("findTargetKeySValue " + e.ToSafeString(), command);
        return null;
    }
}