Skip to main content
All docs
V23.2

How to: Use Azure Key Vault API to Sign a PDF Document

  • 7 minutes to read

This example demonstrates how to use the Azure Key Vault API to sign a PDF document.

View Example: How to sign a PDF document using Azure Key Vault API

Prerequisites

Obtain a Certificate

Use Azure Key Vault API to obtain a certificate or the whole certificate chain.

The AzureKeyVaultClient class below uses the Azure Key Vault API to retrieve a certificate or a certificate chain, and signs the document hash with a private key stored on Azure.

public class AzureKeyVaultClient
{
    public static AzureKeyVaultClient CreateClient(string keyVaultUrl)
    {
        return new AzureKeyVaultClient(new KeyClient(new Uri(keyVaultUrl), new DefaultAzureCredential()));
    }

    readonly KeyClient client;

    DefaultAzureCredential defaultAzureCredential;
    AzureKeyVaultClient(KeyClient client)
    {
        this.client = client;

        var credentialOptions = new DefaultAzureCredentialOptions
        {
            ExcludeInteractiveBrowserCredential = false,
            ExcludeVisualStudioCodeCredential = true
        };
        defaultAzureCredential = new DefaultAzureCredential(credentialOptions);
    }
    public byte[] Sign(string keyId, SignatureAlgorithm algorithm, byte[] digest)
    {
        KeyVaultKey cloudRsaKey = client.GetKey(keyId);
        var rsaCryptoClient = new CryptographyClient(cloudRsaKey.Id, defaultAzureCredential);

        SignResult rsaSignResult = rsaCryptoClient.Sign(algorithm, digest);
        Debug.WriteLine($"Signed digest using the algorithm {rsaSignResult.Algorithm}, with key {rsaSignResult.KeyId}. " +
            $"The resulting signature is {Convert.ToBase64String(rsaSignResult.Signature)}");

        return rsaSignResult.Signature;
    }

    public byte[] GetCertificateData(string keyVaultUrl, string certificateIdentifier)
    {
        var certificateClient = new CertificateClient(new Uri(keyVaultUrl), defaultAzureCredential);
        KeyVaultCertificateWithPolicy cert = certificateClient.GetCertificate(certificateIdentifier);

        return cert.Cer;
    }

}

Create a Pkcs7SignerBase descendant to create a custom signer class. This class helps you to retrieve a certificate or a certificate chain, and sign the document hash. To calculate the document hash, you can use the DigestCalculator class. This class supports the following hashing algorithms: SHA1, SHA256, SHA384, and SHA512. Override the Pkcs7SignerBase.DigestCalculator property to return a DigestCalculator instance.

The code sample below shows the AzureKeyVaultSigner class that is the Pkcs7SignerBase descendant. The SignDigest method overload calls the AzureKeyVaultClient.Sign method to sign the calculated document hash with a private key (specified by the keyId variable).

public class AzureKeyVaultSigner : Pkcs7SignerBase
{
    // OID for RSA signature algorithm:
    const string PKCS1RsaEncryption = "1.2.840.113549.1.1.1";

    readonly AzureKeyVaultClient keyVaultClient;
    readonly string keyId;
    readonly byte[][] certificateChain;


    // Must match with key algorithm (RSA or ECDSA)
    // OID for RSA PKCS1RsaEncryption(1.2.840.113549.1.1.1) can have any digest algorithm
    // For ECDSA, use OIDs from this family: http://oid-info.com/get/1.2.840.10045.4.3 
    // Specified digest algorithm must be the same as to DigestCalculator algorithm
    protected override IDigestCalculator DigestCalculator => new DigestCalculator(HashAlgorithmType.SHA256); //Digest algorithm
    protected override string SigningAlgorithmOID => PKCS1RsaEncryption;
    protected override IEnumerable<byte[]> GetCertificates() => certificateChain;

    public AzureKeyVaultSigner(AzureKeyVaultClient keyVaultClient, string certificateIdentifier, string keyId, string keyVaultUri, ITsaClient tsaClient = null,
        IOcspClient ocspClient = null, ICrlClient crlClient = null,
        PdfSignatureProfile profile = PdfSignatureProfile.Pdf) : base(tsaClient, ocspClient, crlClient, profile)
    {
        this.keyVaultClient = keyVaultClient;
        this.keyId = keyId;

        // Get certificate (without a public key) from Azure Key Vault storage
        // or create a new one at runtime
        // You can get the whole certificate chain here
        certificateChain = new byte[][] { keyVaultClient.GetCertificateData(keyVaultUri, certificateIdentifier) };
    }
    protected override byte[] SignDigest(byte[] digest)
    {
        return keyVaultClient.Sign(keyId, SignatureAlgorithm.RS256, digest);
    }
}

Sign the Document

Pass the Pkcs7SignerBase descendant object to the PdfSignatureBuilder object constructor to apply a signature to a new form field. Call the PdfDocumentSigner.SaveDocument(String, PdfSignatureBuilder[]) method and pass the PdfSignatureBuilder object as the method parameter to sign the document and save the result.

using DevExpress.Office.DigitalSignatures;
using DevExpress.Office.Tsp;
using DevExpress.Pdf;
using System;
using System.Diagnostics;
// ...
using (var signer = new PdfDocumentSigner(@"Document.pdf"))
{
    // Create a timestamp:
    ITsaClient tsaClient = new TsaClient(new Uri(@"https://freetsa.org/tsr"), HashAlgorithmType.SHA256);

    // Specify the signature's field name and location:
    int pageNumber = 1;
    var description = new PdfSignatureFieldInfo(pageNumber);
    description.Name = "SignatureField";
    description.SignatureBounds = new PdfRectangle(10, 10, 50, 150);

    // Specify your Azure Key Vault URL - (vaultUri)
    const string keyVaultUrl = "";

    // Specify the Azure Key Vault Certificate ID (certId)
    string certificateId = "";

    // Specify the Azure Key Vault Key ID for a certificate
    string keyId = "";

    // Create a custom signer object:
    var client = AzureKeyVaultClient.CreateClient(keyVaultUrl);
    AzureKeyVaultSigner azureSigner = new AzureKeyVaultSigner(client, certificateId, keyId, keyVaultUrl, tsaClient);

    // Apply a signature to a new form field:
    var signatureBuilder = new PdfSignatureBuilder(azureSigner, description);

    // Specify an image and signer information:
    signatureBuilder.SetImageData(System.IO.File.ReadAllBytes("signature.jpg"));
    signatureBuilder.Location = "LOCATION";

    // Sign and save the document:
    string output = "SignedDocument.pdf";
    signer.SaveDocument(output, signatureBuilder);
    Process.Start(new ProcessStartInfo(output) { UseShellExecute = true });
}