Создать подпись с помощью Pkcs11Interop без токена-пароля

Я использую Pkcs11Interop в сочетании с сертификатом на USB-накопителе для подписи PDF-документов.

Для подписания документа выполняются следующие шаги:

  • Загрузите библиотеку pkcs11 (LoadPkcs11Library)
  • Получить слот выбранной смарт-карты/USB-токена
  • OpenSession в слоте (требуется штифт слота)
  • Выполнить вход в сеанс
  • Найдите дескриптор закрытого ключа
  • подписать документ (требуется булавка)

Соответствующий код:

        private byte[] GetSignatureFromHashViaPkcs11(byte[] hash, string pin)
        {
            Pkcs11InteropFactories factories = new Pkcs11InteropFactories();
            using (IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, PKCS11LibPath, AppType.SingleThreaded))
            {
                ISlot slot = LoadSlot(pkcs11Library, CertificateToUse.BelongsToSmartCardSlot.TokenSerial);
                using (ISession session = slot.OpenSession(SessionType.ReadOnly))
                {
                    session.Login(CKU.CKU_USER, pin);

                    //Search the private key based on the pulblic key CKA_ID
                    IObjectHandle keyHandle = null;
                    var searchTemplate = new List<IObjectAttribute>()
                    {
                        //CKO_PRIVATE_KEY in order to get handle for the private key
                        session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
                        //CKA_ID searching for the private key which matches the public key
                        session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, CertificateToUse.PublicKeyCKAID.GetValueAsByteArray()),
                    };

                    //filter the search result. Since we search for a private key, only one is returned for each certificate
                    var search = session.FindAllObjects(searchTemplate);
                    keyHandle = search.FirstOrDefault();

                    if (keyHandle == null || (keyHandle.ObjectId == CK.CK_INVALID_HANDLE))
                    {
                        throw new Exception("Unable to read SmartCard KeyHandle. Make sure the correct PKCS11 Library is used");
                    }

                    try
                    {
                        //Create the signature (using the pin)
                        var pinAsByteArray = UTF8Encoding.UTF8.GetBytes(pin);
                        using (IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_SHA256_RSA_PKCS))
                            return session.Sign(mechanism, keyHandle, pinAsByteArray, hash);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Error creating the signature", ex);
                    }
                }
            }
        }

Это решение работает, если пин-код слота и пин-код закрытого ключа совпадают. В случае, если эти контакты отличаются, приведенный выше код не работает, поскольку используется только один контакт.

Если я управляю пин-кодом слота и пин-кодом закрытого ключа вручную в коде, все работает.

Но кажется, что должна быть возможность создать подпись, не выполняя перед этим OpenSession. У моего клиента есть старый инструмент, которому для подписания документа требуется только пин-код закрытого ключа (что означает, что технически возможно подписать без пин-кода слота).

Моя проблема в том, что в настоящее время мне требуется выполнить сеанс. Войдите в систему с помощью булавки слота, чтобы получить дескриптор закрытого ключа.

Вопрос: Есть ли другой способ подписать документ с помощью Pkcs11Interop без необходимости сначала выполнять сеанс session.Login. Или есть другой способ получить дескриптор закрытого ключа без необходимости сначала выполнять session.Login?

0 ответов

Другие вопросы по тегам