Введение и мотивация

При внедрении цифровых подписей в корпоративных системах безопасность является неотъемлемой.
Хранение сертификата в локальном файле PFX или P12 удобно, но подвергает закрытый ключ риску извлечения или компрометации. В отличие от этого, аппаратные токены PKCS#11 (например, USB‑донглы, смарт‑карты и HSM) хранят ключи внутри защищённого от вмешательства окружения, гарантируя, что они никогда не покидают устройство.

Эта статья демонстрирует, как использовать GroupDocs.Signature for .NET совместно с Pkcs11Interop для подписи PDF‑документов аппаратными токенами. Подход сочетает удобство и соответствие требованиям: GroupDocs обрабатывает всё, что связано с упаковкой PDF (поля подписи, вычисление дайджеста, внедрение), а токен выполняет собственно криптографическую подпись.

⚠️ Уведомление о ранней реализации
Это решение предоставляется как ранняя реализация для использования USB‑донглов цифровой подписи PKCS#11 с GroupDocs.Signature.
Хотя оно позволяет подписывать документы аппаратными токенами, мы настоятельно рекомендуем провести дополнительные тесты в вашей среде, чтобы убедиться, что решение соответствует вашим требованиям к соответствию и безопасности.
Мы будем признательны за ваш отзыв, результаты тестов и предложения по улучшению.

Задача: интеграция PKCS#11 с подписанием PDF

Интеграция токенов PKCS#11 в рабочие процессы подписи документов сопряжена с несколькими нетривиальными проблемами:

  1. Низкоуровневая сложность — API PKCS#11 (Cryptoki) требует управления слотами, сессиями, дескрипторами и атрибутами для поиска нужного закрытого ключа.
  2. Упаковка на уровне PDF — Подпись PDF‑файла это больше, чем простая подпись байтов: библиотека должна вычислять корректные дайджесты по выбранным диапазонам байтов, оборачивать подписи в контейнеры CMS/PKCS#7, включать метки времени и внедрять информацию о проверке.
  3. Вариации поставщиков — Разные токены/модули могут требовать пользовательского сопоставления атрибутов или дополнительного промежуточного программного обеспечения.
  4. Соответствие и аудит — В продукционных системах необходим надёжный ввод PIN‑кода, контроль жизненного цикла сессий, восстановление после ошибок и ведение журналов.

Этот примеровый проект решает указанные проблемы, сочетая интерфейс ICustomSignHash в GroupDocs.Signature с Pkcs11Interop, передавая процесс подписи токену, а GroupDocs берёт на себя работу с PDF‑структурой.

Что делает примеровый проект

  • Демонстрирует подпись PDF‑документов с помощью токенов PKCS#11 (донгл, смарт‑карта, HSM).
  • Поддерживает резервный вариант хранилища сертификатов Windows: если сертификат установлен в Windows, код может использовать его.
  • Реализует пользовательскую подпись хеша: GroupDocs вычисляет дайджест, токен только подписывает хеш.
  • Хранит закрытый ключ на аппаратуре всё время — никогда не экспортируется.
  • Инкапсулирует логику токена (сессия, поиск ключа, подпись) в Pkcs11DigitalSigner.cs.
  • Предоставляет вспомогательную логику в Helpers.cs (например, поиск сертификата в хранилище Windows).
  • Конфигурация централизована в Settings.cs.
  • Служит эталонной реализацией, которую можно адаптировать под вашу среду.
Интеграция PKCS#11 с подписанием PDF

Установка и предварительные требования

Предварительные требования

  • .NET 6.0 или выше (или .NET Framework 4.6.2)
  • Действительная PKCS#11‑библиотека (DLL) от производителя вашего токена
  • Аппаратный токен (USB‑донгл, смарт‑карта или HSM) с действительным сертификатом
  • GroupDocs.Signature for .NET (триальная или лицензированная версия)
  • Библиотека Pkcs11Interop

Установка

git clone https://github.com/groupdocs-signature/esign-documents-with-pkcs11-using-groupdocs-signature-dotnet.git
cd esign-documents-with-pkcs11-using-groupdocs-signature-dotnet
dotnet restore

Откройте решение в Visual Studio или в любимой IDE, убедитесь, что зависимости разрешены.

Структура репозитория в деталях

GroupDocs.Signature-for-.NET-PKCS11-Sample/
├── GroupDocs.Signature-for-.NET-PKCS11-Sample.csproj      # Файл проекта
├── Program.cs                                             # Точка входа и общий поток
├── Settings.cs                                            # Конфигурация PKCS#11 / токена
├── Helpers.cs                                             # Вспомогательные функции (хранилище Windows, фильтрация сертификатов)
├── Pkcs11DigitalSigner.cs                                 # Реализует ICustomSignHash через PKCS#11
└── README.md                                              # Описание и инструкции по использованию
  • Program.cs — оркестрирует процесс подписи; демонстрирует как токен‑базированную, так и поток Windows‑сертификата.
  • Settings.cs — содержит константы/заполнители для Pkcs11LibraryPath, TokenPin и CertificateSubject.
  • Helpers.cs — код для поиска сертификатов в хранилище Windows по имени субъекта (используется в резервном потоке).
  • Pkcs11DigitalSigner.cs — ядро логики: загрузка модуля PKCS#11, открытие сессий, поиск объекта закрытого ключа, подпись дайджеста и возврат X509Certificate2 или реализации обратного вызова подписи.
  • README.md — предоставляет обзор, описание проблем и инструкций (которые дополняет данный блог).

Объяснение кода и пошаговый разбор

Settings.cs

public static class Settings
{
    public const string Pkcs11LibraryPath = "<PKCS11_LIBRARY_PATH>";
    public const string TokenPin = "<TOKEN_PIN>";
    public const string CertificateSubject = "<CERT_SUBJECT>";
}

Этот класс выделяет параметры конфигурации, чтобы их было легко заменить в вашей среде развертывания.

Pkcs11DigitalSigner.cs — общий алгоритм

public class Pkcs11DigitalSigner : ICustomSignHash
{
    public byte[] SignHash(byte[] hash)
    {
        // This method is invoked by GroupDocs.Signature when it needs the token to sign a hash
        using (var pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, AppType.SingleThreaded))
        {
            // Load module, open session, login with PIN, find key and perform signing
        }
    }

    public X509Certificate2 GetCertificateFromPkcs11()
    {
        // Retrieves the public certificate from the token so the signing options can be configured
    }
}
  • SignHash — центральный метод: получает дайджест, вычисленный GroupDocs, а затем использует API PKCS#11 для его подписи.
  • GetCertificateFromPkcs11 — извлекает сертификат (с публичным ключом) из токена, чтобы метаданные подписи были корректными.

Program.cs — порядок работы

class Program
{
    static void Main()
    {
        string inputFile = "sample.pdf";
        string outputFile = "signed.pdf";

        // (1) PKCS#11 signing
        var tokenSigner = new Pkcs11DigitalSigner();
        var cert = tokenSigner.GetCertificateFromPkcs11();

        using (var signature = new Signature(inputFile))
        {
            var options = new DigitalSignOptions(cert)
            {
                Comments = "Signed with PKCS#11 token",
                SignTime = DateTime.Now,
                CustomSignHash = tokenSigner  // link token-based signing
            };
            signature.Sign(outputFile, options);
        }

        // (2) Windows certificate store fallback (optional)
        // var storeCert = Helpers.GetCertificateFromWindowsStore(Settings.CertificateSubject);
        // using (var signature2 = new Signature(inputFile))
        // {
        //     var options2 = new DigitalSignOptions(storeCert) { ... };
        //     signature2.Sign("signed_store.pdf", options2);
        // }
    }
}

Ключевые моменты:

  • Свойство CustomSignHash у DigitalSignOptions задаётся как tokenSigner, что позволяет GroupDocs делегировать реальную подпись хеша токену.
  • Резервный поток (закомментировано) показывает, как переключиться на сертификат из хранилища Windows, если аппаратный токен недоступен.

Сценарии применения и реальные кейсы

  • Индия и USB‑донглы, выданные ЦА
    В Индии многие юридически значимые электронные подписи требуют сертификатов, хранящихся в USB‑донглах, выданных сертифицированными органами. Этот пример позволяет приложениям (например, шлюзам документов, порталам) интегрироваться напрямую с такими донглами.
  • Корпоративные рабочие потоки с документами
    Для внутренних систем, таких как договорный менеджмент или процессы согласования, аппаратная подпись гарантирует, что неавторизованные пользователи не смогут подделать подписи.
  • Юридические и регулируемые подписи
    Правительства и отрасли с высоким уровнем регулирования часто требуют, чтобы подписи исходили из ключей, управляемых оборудованием. Интеграция помогает выполнить строгие требования аудита и соответствия.

Частые ошибки и диагностика

  • Неправильный путь к библиотеке → Путь к DLL PKCS#11 должен точно соответствовать модулю поставщика (например, softhsm2.dll, cryptoki.dll).
  • Блокировка или ошибка PIN‑кода → Многократные неверные вводы могут заблокировать токен; ознакомьтесь с политикой поставщика.
  • Ключ не найден → Убедитесь, что указано правильное значение субъекта сертификата; токен должен содержать сертификат с совпадающим субъектом.
  • Отсутствие драйвера или промежуточного ПО → Некоторые токены требуют установки драйверов поставщика перед тем, как Pkcs11Interop сможет установить связь.
  • Проблемы с потоками → Операции PKCS#11 могут быть не потокобезопасными; используйте однопоточный контекст, если поставщик не поддерживает многопоточность.
  • Тайм‑ауты или сброс сессии → Длинные операции могут привести к закрытию сессии; обеспечьте корректную обработку сессий и их очистку.

Безопасность и рекомендации лучшей практики

  • Никогда не зашивайте в код производственные секреты (PIN‑коды, пути к библиотекам); используйте безопасные конфиги или системы управления секретами.
  • Применяйте сильные PIN‑коды и периодически их меняйте в соответствии с политиками.
  • Ведите журнал операций и ошибок (без записи чувствительных PIN‑кодов).
  • Ограничивайте количество сессий токена и завершайте их сразу после подписи.
  • Проверяйте подпись после её создания (проверка цепочки, метка времени).
  • Тестируйте в разных окружениях и с разными типами токенов (донгл/смарт‑карта/HSM).

Далее: шаги и ресурсы

Готовы попробовать? Клонируйте репозиторий, замените заполнители и запустите пример.
Темы, которые могут быть интересны дальше:

  • Пользовательская подпись хеша (делегирование вычисления дайджеста и подписи токену)
  • Метки времени и встраивание LTV / DSS
  • Итеративная подпись (несколько подписей в одном документе)
  • Интеграция с удалёнными HSM‑службами или облачными хранилищами токенов

Внешние ссылки