このページには自動翻訳されたテキストを含めることができます。

USB トークンと HSM デバイスを使用して C# と VB.NET で PDF に署名する方法

信頼された認証局は、文書署名証明書の秘密鍵のエクスポートをもはや許可しません。代わりに、秘密鍵は USB トークン、スマートカード、またはクラウドベースの HSM などの安全なハードウェアに格納する必要があります。

Docotic.Pdf ライブラリ を使用すると、HSM デバイスを使って .NET で PDF 文書に署名できます。この記事では、Azure Key Vault、AWS KMS、および PKCS#11 準拠のハードウェアとの統合について説明します。

ライブラリと、期間限定の無料ライセンスキーを C# .NET PDF ライブラリをダウンロード ページで取得できます。

外部 PDF 署名

前提条件

この記事のコードサンプルでは、自己署名証明書を使用して PDF 文書に署名します。既定では、PDF ビューアーはこれらの署名を信頼しません。自己署名証明書はテスト専用に使用し、本番環境では使用しないでください。信頼できる PDF 署名を生成するには、サードパーティの認証局が発行した文書署名証明書を使用します。

適切な証明書を取得する

Adobe Approved Trust List (AATL) に掲載されている企業の証明書を優先してください。Adobe Acrobat は、既定でそのような企業の証明書を信頼し、"Certificate validity is unknown" 警告を表示しません。

EU (eIDAS) 準拠の文書を作成するには、European Union Trusted Lists (EUTL) に掲載されているプロバイダーが発行した Qualified Certificate を使用する必要があります。

.NET で証明書の使い方を学ぶ

文書署名証明書を注文すると、通常は HSM デバイスへのアクセスが提供されます。これは物理的な USB トークン、またはクラウドベースの HSM ソリューションの場合があります。

次に、この HSM を使ってデータに署名する方法を学ぶ必要があります。暗号プロバイダーはすべて異なるため、これは通常、最も難しい部分です。USB トークンまたはクラウド API のドキュメントに従ってください。

理想的には、対応する .NET SDK を見つける必要があります。少なくとも、ネイティブ SDK を見つけて .NET から interop 経由で使用してください。

目標は、証明書を使って任意のバイト列に署名できる C# または VB.NET のコードを得ることです。

外部署名用 PDF API

HSM デバイスで任意のバイト列に署名できるようになったら、Docotic.Pdf で PDF 文書に署名する準備は完了です。そのためには、IPdfSigner インターフェイス を実装し、署名に使用します。

IPdfSigner インターフェイスを実装する

IPdfSigner には 2 つのメンバーが定義されています。SignatureAlgorithm プロパティは、署名に使用するアルゴリズムを返します。通常は RSA または ECDSA アルゴリズムを使用します。

Sign メソッドは、外部署名フローの中核です。Docotic.Pdf は PDF 文書のバイト列のダイジェストをこのメソッドに渡します。このダイジェストに HSM デバイスで署名し、デジタル署名のバイト列を返す必要があります。ここでは PKCS#7 オブジェクトを返してはいけません。暗号署名のみを生成して返してください。

Docotic.Pdf は、各署名に対して Sign メソッドを 2 回呼び出します。1 回目は署名に必要な領域を計算するためです。2 回目は実際に文書に署名するためです。

外部署名用に PdfSigningOptions を作成する

IPdfSigner 実装を使って PDF 文書に署名するには、PdfSigningOptions(IPdfSigner, X509Certificate2[]) コンストラクター を使用します。証明書チェーンを取得し、2 番目の引数として渡します。少なくとも 1 つの証明書が必要で、署名証明書は先頭に置く必要があります。

最後に重要なのは PdfSigningOptions.DigestAlgorithm プロパティです。この値は IPdfSigner.SignatureAlgorithm および IPdfSigner.Sign の実装と一致している必要があります。

一般的なシナリオで外部署名を使って PDF に署名する方法を確認しましょう。

C# で PKCS#11 ドライバーを使用して PDF 文書に署名する

暗号 USB トークンやスマートカードに PKCS#11 ドライバーが付属している場合は、.NET で Pkcs11Interop.X509Store または Pkcs11Interop ライブラリを使用できます。Pkcs11Interop は、Atos CardOS スマートカード、YubiKey PIV、SmartCard-HSM、SafeNet ProtectServer HSM、およびその他の HSM と互換性があります。

PKCS#11 ドライバーを使用して PDF ドキュメントに署名する コードサンプルでは、USB トークンまたはスマートカードを使って PDF 文書に署名する方法を示しています。次の行はカスタマイズする必要があります。

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;

サンプル構成では、USB トークンのエミュレーターとして SoftHSM2 を使用しています。実際のアプリケーションでは SoftHSM2 は不要です。代わりに、USB トークンに付属するドライバーを使用してください。

Azure Key Vault を使用して PDF 文書に署名する

Microsoft Azure Key Vault は、証明書とキーを安全に保管します。次の準備が必要です。

  1. Azure アカウントを作成する。
  2. Azure ユーザーを作成する。
  3. Key Vault を作成する。
  4. 選択した Azure ユーザーに Key Vault へのアクセスを許可する。
  5. Key Vault に文書署名証明書を追加する。統合認証局から証明書を import できます。

次に、.NET で署名するために Azure.Security.KeyVault.Keys NuGet パッケージを使用します。Azure Key Vault のキーを使って署名する C# サンプルコードは次のとおりです。

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, ..);

GitHub で Azure Key Vault を使用して PDF ドキュメントに署名する の完全なコードサンプルを確認してください。

AWS KMS を使用して PDF 文書に署名する

AWS Key Management Service (KMS) も、暗号鍵を安全に保管するための仕組みです。準備手順は Azure Key Vault と同じです。

  1. AWS アカウントを作成する。
  2. IAM ユーザーを作成する。
  3. 署名キーを追加する。
  4. 選択した IAM ユーザーにキーへのアクセスを許可する。

AWS では、.NET で AWSSDK.KeyManagementService NuGet パッケージを使用する必要があります。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();
    }
}

完全な AWS KMS を使用して PDF ドキュメントに署名する コードサンプルも GitHub で入手できます。

結論

Docotic.Pdf ライブラリ を活用すると、USB トークン、スマートカード、またはクラウドベースの HSM を使用して PDF 文書に署名できます。これを実現するには、C# または VB.NET のコードで IPdfSigner インターフェイスを実装します。

GitHub から PDF でのデジタル署名用コードサンプル をダウンロードして試してください。関連情報については、次の記事を確認してください。

よくある質問

USB トークンまたはスマートカードを使用して PDF に署名するにはどうすればよいですか?

Docotic.Pdf と Pkcs11Interop .NET ライブラリを使用して、トークンまたはスマートカードで PDF に署名します。詳細は C# で PKCS#11 ドライバーを使用して PDF 文書に署名する セクションを参照してください。

USB トークンまたはスマートカードで SoftHSM を使用するにはどうすればよいですか?

SoftHSM は実際の HSM デバイスをシミュレートします。USB トークンまたはスマートカードがある場合は、SoftHSM は不要です。代わりに、HSM デバイスに付属する PKCS#11 ドライバーを使用してください。

外部署名で PDF 文書に署名するにはどうすればよいですか?

Azure Key Vault を使用して PDF 文書に署名するAWS KMS を使用して PDF 文書に署名する セクションを確認してください。その他のクラウドベースの HSM を使った外部 PDF 署名も、同様の手順です。

.NET で Azure Key Vault を使用するにはどうすればよいですか?

Azure.Security.KeyVault.Keys NuGet パッケージを使用します。GitHub の Azure Key Vault を使用して PDF ドキュメントに署名する コードサンプルを試してください。