Вступ та Мотивація

При впровадженні цифрових підписів у корпоративних системах безпека є незаперечною.
Зберігання сертифікату у локальному файлі PFX або P12 зручно, проте піддає приватний ключ ризику витоку або компрометації. Навпаки, апаратні токени PKCS#11 (наприклад USB‑дотики, смарт‑карти та HSM) зберігають ключі всередині стійкої до втручань оболонки, гарантуючи, що вони ніколи не залишають пристрій.

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

⚠️ Попереднє повідомлення про реалізацію
Це рішення наразі надається як рання реалізація використання 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 Certificate Store: якщо сертифікат встановлений у Windows, код може використати його.
  • Реалізує кастомне підписання хешу: GroupDocs обчислює дайджест; токен підписує лише хеш.
  • Тримає приватний ключ на апаратному рівні весь час — ніколи не експортується.
  • Інкапсулює логіку токену (сесія, пошук ключа, підпис) у Pkcs11DigitalSigner.cs.
  • Надає допоміжну логіку у Helpers.cs (наприклад, пошук сертифікату у Windows Store).
  • Конфігурація централізована у 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 Store, фільтрація сертифікатів)
├── Pkcs11DigitalSigner.cs                                 # реалізація ICustomSignHash через PKCS#11
└── README.md                                              # пояснення та інструкції
  • Program.cs — координує процес підписання; демонструє як токен‑базовий, так і Windows‑сертифікатний варіанти.
  • Settings.cs — містить константи/плейсхолдери для Pkcs11LibraryPath, TokenPin та CertificateSubject.
  • Helpers.cs — код пошуку сертифікатів у Windows Store за назвою суб’єкта (використовується у резервному сценарії).
  • 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, і підписує його за допомогою PKCS#11 API.
  • 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 Store, коли апаратний токен недоступний.

Випадки використання та реальні сценарії

  • Індія та USB‑дотики підпису, видані ЦА
    В Індії багато юридично обов’язкових e‑підписів вимагає сертифікати, збережені у USB‑дотиках, виданих акредитованими центрами. Цей приклад дозволяє додаткам (наприклад, шлюзи документів, портали) інтегруватися безпосередньо з такими дотиками.
  • Корпоративні робочі процеси з документами
    Для внутрішніх систем (управління контрактами, процеси затвердження) апаратне підписання гарантує, що неавторизовані користувачі не зможуть підробити підписи.
  • Юридичне / відповідальне підписання
    Урядові органи та регульовані галузі часто вимагають, щоб підписувалися лише ключі, контрольовані апаратурою. Така інтеграція допомагає задовольнити суворі вимоги аудиту та відповідності.

Типові підводні камені та усунення проблем

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

Безпека та найкращі практики

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

Наступні кроки та ресурси

Готові спробувати? Клонуйте репозиторій, замініть заповнювачі та запустіть приклад.
Теми, які варто вивчити далі:

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

Зовнішні посилання