Вступ та Мотивація
При впровадженні цифрових підписів у корпоративних системах безпека є незаперечною.
Зберігання сертифікату у локальному файлі PFX або P12 зручно, проте піддає приватний ключ ризику витоку або компрометації. Навпаки, апаратні токени PKCS#11 (наприклад USB‑дотики, смарт‑карти та HSM) зберігають ключі всередині стійкої до втручань оболонки, гарантуючи, що вони ніколи не залишають пристрій.
Цей пост демонструє, як використати GroupDocs.Signature for .NET разом з Pkcs11Interop для підпису PDF‑документів апаратними токенами. Підхід поєднує зручність та відповідність вимогам: GroupDocs обробляє всю пакувальну логіку на рівні PDF (поля підпису, обчислення дайджесту, вбудовування), а токен виконує фактичне криптографічне підписання.
⚠️ Попереднє повідомлення про реалізацію
Це рішення наразі надається як рання реалізація використання PKCS#11 токенів цифрових підписів разом з GroupDocs.Signature.
Хоча воно дозволяє підписувати документи за допомогою апаратних токенів, ми настійно радимо провести додаткове тестування у вашому середовищі, щоб переконатися, що воно відповідає вашим вимогам щодо відповідності та безпеки.
Ми будемо дуже вдячні за ваші відгуки, результати тестування та пропозиції щодо покращень.
Виклик: з’єднання PKCS#11 з підписанням PDF
Інтеграція токенів PKCS#11 у робочі процеси підписання документів має кілька нетривіальних викликів:
- Складність низького рівня — API PKCS#11 (Cryptoki) вимагає управління слотами, сесіями, дескрипторами та атрибутами для знаходження потрібного приватного ключа.
- Пакування на рівні PDF — підпис PDF – це більше, ніж просте підписання байтів: бібліотека повинна обчислювати правильні дайджести над вибраними діапазонами байтів, обгортати підписи у контейнери CMS/PKCS#7, включати мітки часу й вбудовувати інформацію про валідацію.
- Варіації виробників — різні токени/модулі можуть вимагати кастомного відображення атрибутів або додаткового проміжного ПЗ.
- Відповідність та аудит — у продакшн‑системах потрібне надійне керування PIN‑кодом, контроль життєвого циклу сесії, відновлення після помилок та журналювання.
Цей приклад проєкту вирішує вказані проблеми, об’єднавши інтерфейс ICustomSignHash у GroupDocs.Signature із Pkcs11Interop, щоб делегувати підписування токену, залишаючи GroupDocs відповідальним за структуру PDF.
Що робить приклад проєкту
- Демонструє підписання PDF‑документів за допомогою токенів PKCS#11 (дотик, смарт‑карта, HSM).
- Підтримує резервний варіант Windows Certificate Store: якщо сертифікат встановлений у Windows, код може використати його.
- Реалізує кастомне підписання хешу: GroupDocs обчислює дайджест; токен підписує лише хеш.
- Тримає приватний ключ на апаратному рівні весь час — ніколи не експортується.
- Інкапсулює логіку токену (сесія, пошук ключа, підпис) у
Pkcs11DigitalSigner.cs. - Надає допоміжну логіку у
Helpers.cs(наприклад, пошук сертифікату у Windows Store). - Конфігурація централізована у
Settings.cs. - Служить прикладом референс‑реалізації, яку можна адаптувати під ваші потреби.
Налаштування та вимоги
Вимоги
- .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‑сервісами або хмарними сховищами токенів