Эта страница может содержать автоматически переведенный текст.
Как подписывать PDF-файлы с USB-токенами и устройствами HSM в C# и VB.NET
Доверенные центры сертификации больше не разрешают экспортировать закрытые ключи для сертификатов подписи документов. Вместо этого закрытые ключи должны храниться в защищенном оборудовании, таком как USB-токены, смарт-карты или облачные HSM.
Вы можете использовать библиотеку Docotic.Pdf для подписания PDF-документов в .NET с использованием устройств HSM. В этой статье описаны интеграции с Azure Key Vault, AWS KMS и оборудованием, совместимым с PKCS#11.
Вы можете получить библиотеку и бесплатный лицензионный ключ с ограниченным сроком действия на странице Скачать C# .NET библиотеку PDF.

Предварительные условия
Примеры кода в этой статье используют самоподписанные сертификаты для подписания PDF-документов. По умолчанию просмотрщики PDF не доверяют таким подписям. Самоподписанные сертификаты следует использовать только для тестирования, а не в рабочих средах. Чтобы создавать доверенные PDF-подписи, используйте сертификаты подписи документов, выпущенные сторонними центрами сертификации.
Выберите подходящий сертификат
Предпочтительно использовать сертификаты от компаний, перечисленных в списке доверенных сертификатов Adobe (AATL). Adobe Acrobat по умолчанию доверяет сертификатам таких компаний и не будет показывать предупреждение «Срок действия сертификата неизвестен».
Чтобы создавать документы, соответствующие требованиям ЕС (eIDAS), необходимо использовать квалифицированные сертификаты, выпущенные поставщиками, перечисленными в доверенных списках Европейского союза (EUTL).
Узнайте, как использовать ваш сертификат в .NET
Когда вы заказываете сертификат подписи документов, обычно вы получаете доступ к устройству HSM. Это может быть физический USB-токен или облачное решение HSM.
Затем вам следует научиться подписывать данные с помощью этого HSM. Обычно это самая сложная часть, потому что все криптопровайдеры различаются. Вам следует обратиться к документации для вашего USB-токена или облачного API.
В идеале нужно найти соответствующий .NET SDK. Или, по крайней мере, найти нативный SDK и использовать его через interop в .NET.
Ваша цель — получить код на C# или VB.NET, который может подписывать любые байты с использованием вашего сертификата.
PDF API для внешнего подписывания
После того как вы сможете подписывать любые байты с помощью вашего устройства HSM, вы будете готовы подписывать PDF-документы с помощью Docotic.Pdf. Для этого реализуйте интерфейс IPdfSigner и используйте его для подписания.
Реализуйте интерфейс IPdfSigner
IPdfSigner объявляет два члена. Свойство SignatureAlgorithm возвращает алгоритм, используемый для подписи. Обычно используются алгоритмы RSA или ECDSA.
Метод Sign — ключевая часть потока внешнего подписывания. Docotic.Pdf передает этому методу дайджест байтов PDF-документа. Вам нужно подписать этот дайджест с помощью вашего устройства HSM и вернуть байты цифровой подписи. Обратите внимание, что здесь нельзя возвращать объект PKCS#7. Просто создайте и верните криптографическую подпись.
Docotic.Pdf вызывает метод Sign дважды для каждой подписи. Первый вызов нужен для расчета пространства, необходимого для подписи. Второй вызов — для фактического подписания документа.
Создайте PdfSigningOptions для внешнего подписывания
Используйте конструктор PdfSigningOptions(IPdfSigner, X509Certificate2[]) для подписания PDF-документов с вашей реализацией IPdfSigner. Получите цепочку сертификатов и передайте ее вторым аргументом. Требуется как минимум один сертификат, и первым должен идти сертификат подписи.
Последний элемент головоломки — свойство PdfSigningOptions.DigestAlgorithm. Значение этого свойства должно соответствовать IPdfSigner.SignatureAlgorithm и реализации IPdfSigner.Sign.
Давайте рассмотрим, как подписывать PDF-файлы внешними подписями в распространенных сценариях.
Подписывайте PDF-документы с помощью драйвера PKCS#11 в C#
Если ваш криптографический USB-токен или смарт-карта поставляется с драйвером PKCS#11, вы можете использовать библиотеки Pkcs11Interop.X509Store или Pkcs11Interop в .NET. Pkcs11Interop совместим со смарт-картами Atos CardOS, YubiKey PIV, SmartCard-HSM, SafeNet ProtectServer HSM и другими HSM.
Пример кода Подписывайте PDF-документы с помощью драйвера PKCS#11 показывает, как подписывать PDF-документы с помощью USB-токена или смарт-карты. Вам нужно будет настроить следующие строки:
string pkcsLibraryPath = @"C:\Program Files\SoftHSM2\lib\softhsm2-x64.dll";
ulong slotId = 1743347971;
string alias = "YOUR-ALIAS";
string certLabel = "YOUR-CERTIFICATE";
string pin = "YOUR-PIN";
var digestAlgorithm = PdfDigestAlgorithm.Sha512;
В нашей конфигурации примера SoftHSM2 используется как эмулятор USB-токена. В реальных приложениях SoftHSM2 не нужен. Вместо этого используйте драйвер, поставляемый с USB-токеном.
Подписывайте PDF-документы с помощью Azure Key Vault
Microsoft Azure Key Vault надежно хранит сертификаты и ключи. Вам потребуется выполнить следующие действия:
- Создайте учетную запись Azure.
- Создайте пользователя Azure.
- Создайте Key Vault.
- Разрешите доступ к Key Vault выбранному пользователю Azure.
- Добавьте сертификат подписи документа в Key Vault. Вы можете импортировать сертификаты из интегрированных центров сертификации.
Затем используйте пакет NuGet Azure.Security.KeyVault.Keys для подписания в .NET. Пример кода на C# для подписания с использованием ключа из Azure Key Vault:
var vaultUrl = new Uri("https://YOUR-VAULT.vault.azure.net/");
var credentials = new DefaultAzureCredential();
var keyClient = new KeyClient(vaultUrl, credentials);
KeyVaultKey key = keyClient.GetKey("YOUR-KEY");
var cryptoClient = new CryptographyClient(key.Id, credentials);
byte[] messageToSign = ..;
byte[] signature = cryptoClient.SignData(SignatureAlgorithm.RS512, messageToSign).Signature;
Связанная реализация IPdfSigner может выглядеть так:
using AzureSignatureAlgorithm = SignatureAlgorithm;
class AzureSigner : IPdfSigner
{
private readonly CryptographyClient m_client;
private readonly AzureSignatureAlgorithm m_signingAlgorithm;
public AzureSigner(CryptographyClient client, AzureSignatureAlgorithm signingAlgorithm)
{
m_client = client;
m_signingAlgorithm = signingAlgorithm;
}
public PdfSignatureAlgorithm SignatureAlgorithm
{
get
{
if (m_signingAlgorithm == AzureSignatureAlgorithm.RS256 ||
m_signingAlgorithm == AzureSignatureAlgorithm.RS384 ||
m_signingAlgorithm == AzureSignatureAlgorithm.RS512)
return PdfSignatureAlgorithm.Rsa;
throw new NotSupportedException($"Unsupported {nameof(SignatureAlgorithm)} value: {m_signingAlgorithm}");
}
}
public PdfDigestAlgorithm DigestAlgorithm
{
get
{
if (m_signingAlgorithm == AzureSignatureAlgorithm.RS256)
return PdfDigestAlgorithm.Sha256;
if (m_signingAlgorithm == AzureSignatureAlgorithm.RS384)
return PdfDigestAlgorithm.Sha384;
if (m_signingAlgorithm == AzureSignatureAlgorithm.RS512)
return PdfDigestAlgorithm.Sha512;
throw new NotSupportedException($"Unsupported {nameof(SignatureAlgorithm)} value: {m_signingAlgorithm}");
}
}
public byte[] Sign(byte[] message)
{
return m_client.SignData(m_signingAlgorithm, message).Signature;
}
}
Наконец, используйте этот класс AzureSigner для подписания PDF-документов:
CryptographyClient cryptoClient = ..;
using X509Certificate2 cert = ..;
var signer = new AzureSigner(cryptoClient, SignatureAlgorithm.RS512);
using var pdf = new PdfDocument();
PdfPage page = pdf.Pages[0];
PdfSignatureField field = page.AddSignatureField(50, 50, 200, 200);
var options = new PdfSigningOptions(signer, [cert])
{
DigestAlgorithm = signer.DigestAlgorithm,
Field = field,
};
pdf.SignAndSave(options, ..);
Ознакомьтесь с полным примером кода Подписывайте PDF-документы с помощью Azure Key Vault. на GitHub.
Подписывайте PDF-документы с помощью AWS KMS
AWS Key Management Service (KMS) — это еще одно защищенное хранилище для криптографических ключей. Подготовка выполняется по тем же шагам, что и для Azure Key Vault:
- Создайте учетную запись AWS.
- Создайте пользователя IAM.
- Добавьте ключ подписи.
- Разрешите доступ к ключам выбранному пользователю IAM.
Для AWS вам потребуется использовать пакет NuGet AWSSDK.KeyManagementService в .NET. Пример кода для подписания PDF довольно близок к сценарию Azure:
using var pdf = new PdfDocument();
PdfPage page = pdf.Pages[0];
PdfSignatureField field = page.AddSignatureField(50, 50, 200, 200);
var signingAlgorithm = SigningAlgorithmSpec.RSASSA_PSS_SHA_512;
var signer = new AwsSigner("arn:aws:kms:YOUR-id", signingAlgorithm);
var options = new PdfSigningOptions(signer, [cert])
{
DigestAlgorithm = signer.DigestAlgorithm,
Field = field,
};
pdf.SignAndSave(options, ..);
class AwsSigner : IPdfSigner
{
private readonly string m_keyId;
private readonly SigningAlgorithmSpec m_signingAlgorithm;
public AwsSigner(string keyId, SigningAlgorithmSpec signingAlgorithm)
{
m_keyId = keyId;
m_signingAlgorithm = signingAlgorithm;
}
public PdfSignatureAlgorithm SignatureAlgorithm
{
get
{
if (m_signingAlgorithm == SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_256 ||
m_signingAlgorithm == SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_384 ||
m_signingAlgorithm == SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_512)
return PdfSignatureAlgorithm.Rsa;
throw new NotSupportedException($"Unsupported {nameof(SigningAlgorithmSpec)} value: {m_signingAlgorithm}");
}
}
public PdfDigestAlgorithm DigestAlgorithm
{
get
{
string alg = m_signingAlgorithm.Value;
if (alg.EndsWith("256"))
return PdfDigestAlgorithm.Sha256;
if (alg.EndsWith("384"))
return PdfDigestAlgorithm.Sha384;
if (alg.EndsWith("512"))
return PdfDigestAlgorithm.Sha512;
throw new NotSupportedException($"Unsupported {nameof(SigningAlgorithmSpec)} value: {m_signingAlgorithm}");
}
}
public byte[] Sign(byte[] message)
{
using var kmsClient = new AmazonKeyManagementServiceClient();
using var stream = new MemoryStream(message);
var signRequest = new SignRequest()
{
SigningAlgorithm = m_signingAlgorithm,
KeyId = m_keyId,
MessageType = MessageType.RAW,
Message = stream,
};
SignResponse signResponse = kmsClient.SignAsync(signRequest).GetAwaiter().GetResult();
return signResponse.Signature.ToArray();
}
}
Полный пример кода Подписывайте PDF-документы с помощью AWS KMS также доступен на GitHub.
Заключение
Используйте библиотеку Docotic.Pdf для подписания PDF-документов с помощью USB-токенов, смарт-карт или облачных HSM. Для этого реализуйте интерфейс IPdfSigner в коде C# или VB.NET.
Скачайте и попробуйте примеры кода для цифровых подписей в PDF с GitHub. См. связанные статьи для дополнительной информации:
- Подписание PDF-документов в C# и VB.NET
- Проверка подписи PDF в C# и VB.NET
- Добавить сведения Long-Term Validation (PAdES-LTV) в подписи PDF в C#
Часто задаваемые вопросы
Как подписать PDF с помощью USB-токена или смарт-карты?
Используйте библиотеки Docotic.Pdf и Pkcs11Interop .NET для подписания PDF с помощью токена или смарт-карты. Подробности см. в разделе Подписывание PDF-документов с помощью драйвера PKCS#11 в C#.
Как использовать SoftHSM с моим USB-токеном или смарт-картой?
SoftHSM имитирует реальное устройство HSM. Если у вас есть USB-токен или смарт-карта, SoftHSM не нужен. Вместо этого используйте драйвер PKCS#11, поставляемый с вашим устройством HSM.
Как подписать PDF-документ внешней подписью?
См. разделы Подписывайте PDF-документы с помощью Azure Key Vault и Подписывайте PDF-документы с помощью AWS KMS. Внешнее подписывание PDF с другими облачными HSM выполняется по схожему сценарию.
Как использовать Azure Key Vault в .NET?
Используйте пакет NuGet Azure.Security.KeyVault.Keys. Попробуйте пример кода Подписывайте PDF-документы с помощью Azure Key Vault. с GitHub.