Создать подпись с помощью 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?