Эта страница может содержать автоматически переведенный текст.

Как подписывать 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 не доверяют таким подписям. Самоподписанные сертификаты следует использовать только для тестирования, а не в рабочих средах. Чтобы создавать доверенные 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 надежно хранит сертификаты и ключи. Вам потребуется выполнить следующие действия:

  1. Создайте учетную запись Azure.
  2. Создайте пользователя Azure.
  3. Создайте Key Vault.
  4. Разрешите доступ к Key Vault выбранному пользователю Azure.
  5. Добавьте сертификат подписи документа в 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:

  1. Создайте учетную запись AWS.
  2. Создайте пользователя IAM.
  3. Добавьте ключ подписи.
  4. Разрешите доступ к ключам выбранному пользователю 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 с помощью 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.