Евгений, приветствую!
Ваш пример очень сильно помог в разработке, действительно удалось подключить библиотеки и подписать текст сертификатом с флешки.
Но при выполнении кода мы столкнулись с другим моментом, мешающим нам полноценно использовать полученную подпись.
Подпись не принимает сторонняя система, с которой мы интегрируемся, причём, строка, подписанная в форме на сайте https://ra.rutoken.ru/devices/signature, принимается (после удаления переноса строк).
Код формирования подписи представлен ниже:
private const uint PKCS7_DETACHED_SIGNATURE = 0x01;
private const string RutokenEcpDllDefaultPath = "rtpkcs11ecp.dll";
public static byte[]? Sign(byte[] array, string pin)
{
// Шаблон для поиска закрытого ключа ГОСТ Р 34.10-2012 (256 бит).
var privateKeyAttributes = new List<ObjectAttribute>
{
// Объект закрытого ключа.
new(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
// Закрытый ключ является объектом токена.
new(CKA.CKA_TOKEN, true),
};
// Шаблон для поиска сертификата ключа подписи.
var certificateAttributes = new List<ObjectAttribute>
{
// Объект сертификата.
new(CKA.CKA_CLASS, CKO.CKO_CERTIFICATE),
// Сертификат является объектом токена.
new(CKA.CKA_TOKEN, true),
// Тип сертификата - X.509
new(CKA.CKA_CERTIFICATE_TYPE, CKC.CKC_X_509),
};
// Инициализировать библиотеку.
Console.WriteLine("Library initialization.");
using var pkcs11 = new Pkcs11(RutokenEcpDllDefaultPath, AppType.MultiThreaded);
// Получить доступный слот.
Console.WriteLine("Checking tokens available.");
var slot = Helpers.GetUsableSlot(pkcs11);
// Открыть RW сессию в первом доступном слоте.
Console.WriteLine("Opening RW session.");
using var session = slot.OpenSession(SessionType.ReadWrite);
// Выполнить аутентификацию Пользователя.
Console.WriteLine("User authentication.");
session.Login(CKU.CKU_USER, pin);
try
{
// Формирование подписи.
Console.WriteLine("Signing...");
// Поиск закрытого ключа на токене.
Console.WriteLine(" Getting private key...");
var privateKeys = session.FindAllObjects(privateKeyAttributes);
// Поиск сертификата на токене.
Console.WriteLine(" Getting certificate...");
var certificates = session.FindAllObjects(certificateAttributes);
// Подпись данных.
var signature = session.PKCS7Sign(array,
certificates[0], privateKeys[0], null, PKCS7_DETACHED_SIGNATURE);
return signature;
}
finally
{
// Сбросить права доступа как в случае исключения,
// так и в случае успеха.
// Сессия закрывается автоматически.
session.Logout();
}
}
В результате выполнения метода
var accessTokenAsBytes = Encoding.UTF8.GetBytes(accessToken);
var signatureAsBytes = Sign(accessTokenAsBytes, pin);
мы получаем base64-строку с подписью, подпись декодируется через КриптоПро CSP.
Мы предполагаем, что проблема с исходными данными или кодированием в byte[] для session.PKCS7Sign().
Прошу Вас подсказать, если есть такая возможность, как вызывать метод PKCS7Sign() таким образом, чтобы результат подписи получался такой же, как при вызове формы на сайте.