facebooktwittermenuarrow-up

GemBox Support Forum

How to use with CloudHSM

Hi there!

Right now I am using GemBox.pdf to add a signature to my PDF using a YubicoKey.

In future, I would like to use a CloudHSM service (Google KMS) to sign my PDF documents.
This means that my private key will be in the cloud instead of on my YubicoKey.

Is there any documented example how to sign using a CloudHSM?
I do not find any information about how to add a hash digest manually.

Hi,

We didn’t try using AWS CloudHSM nor Google KMS but based on our review of those products, both should be able to integrate with GemBox.Pdf.

For AWS CloudHSM, you should use their PKCS#11 Library. Based on their Installing instructions, Windows binaries of the PKCS #11 Library for Client SDK 5 will be located in ‘C:\ProgramFiles\Amazon\CloudHSM’. You must specify a path to a DLL file contained in this directory when creating an instance of a PdfPkcs11Module class.

Note that you must bootstrap Client SDK 5. For more information about bootstrapping, see Bootstrapping the Client SDK.

Also, note that the PIN that you specify in the PdfPkcs11Token.Login method must be in a format as specified in the Authenticating to the PKCS #11 Library page.

If their implementation of PKCS#11 standard is correct, the rest of the code from the example PDF digital signature with PKCS#11 (Cryptoki) device in C# and VB.NET should work as expected (as long as you provide the correct values for token label and certificate subject common name from your ASW CloudHSM that are used in that example).

For Google KMS, you must use their client library for C# as explained in the Cloud KMS Client Libraries page.

After that, you should use a combination of a code in the Creating and validating digital signatures page and the Digitally sign a PDF file with an external signature example like in the following code snippet:

using System;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using GemBox.Pdf;
using GemBox.Pdf.Forms;
using GemBox.Pdf.Security;
using Google.Cloud.Kms.V1;
using Google.Protobuf;

class Program
{
    static void Main()
    {
        // If using Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        using (var document = PdfDocument.Load("Reading.pdf"))
        {
            // Add a visible signature field to the first page of the PDF document.
            var signatureField = document.Form.Fields.AddSignature(document.Pages[0], 300, 500, 250, 50);

            // Get a digital ID from Google Cloud KMS.
            var digitalId = new GoogleCloudKMSDigitalId();

            // Create a PDF signer that will create the digital signature.
            var signer = new PdfSigner(digitalId);
            
            // Initiate signing of a PDF file with the specified signer.
            signatureField.Sign(signer);

            // Finish signing of a PDF file.
            document.Save("Google Cloud KMS Digital Signature.pdf");
        }
    }
}

/// <summary>
/// Represents a digital ID that uses Google Cloud KMS to create a digital signature.
/// </summary>
/// <seealso href="https://cloud.google.com/kms/docs/create-validate-signatures">Creating and validating digital signatures</seealso>
class GoogleCloudKMSDigitalId : PdfDigitalId
{
    private readonly KeyManagementServiceClient client;
    private readonly CryptoKeyVersionName keyVersionName;

    public GoogleCloudKMSDigitalId(string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123") : this(KeyManagementServiceClient.Create(), new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId))
    {
    }

    private GoogleCloudKMSDigitalId(KeyManagementServiceClient client, CryptoKeyVersionName keyVersionName) : base(GetCertificate(client, keyVersionName))
    {
        this.client = client;
        this.keyVersionName = keyVersionName;
    }

    // See: https://cloud.google.com/kms/docs/retrieve-public-key
    private static PdfCertificate GetCertificate(KeyManagementServiceClient client, CryptoKeyVersionName keyVersionName)
    {
        var result = client.GetPublicKey(keyVersionName);

        return new PdfCertificate(new X509Certificate2(Encoding.ASCII.GetBytes(result.Pem)));
    }

    protected override byte[] SignHash(byte[] hash, PdfHashAlgorithm hashAlgorithm, PdfRSASignaturePadding rsaSignaturePadding)
    {
        // Build the digest.
        Digest digest = new Digest();
        switch (hashAlgorithm)
        {
            case PdfHashAlgorithm.SHA256:
                digest.Sha256 = ByteString.CopyFrom(hash);
                break;

            case PdfHashAlgorithm.SHA384:
                digest.Sha384 = ByteString.CopyFrom(hash);
                break;

            case PdfHashAlgorithm.SHA512:
                digest.Sha512 = ByteString.CopyFrom(hash);
                break;

            default:
                throw new NotSupportedException();
        }

        // Call the API.
        AsymmetricSignResponse result = this.client.AsymmetricSign(this.keyVersionName, digest);

        // Get the signature.
        byte[] signature = result.Signature.ToByteArray();

        // Return the result.
        return signature;
    }
}

The only problematic part might be the retrieval of the X509 certificate that contains the public key associated with the private key (which is securely stored in AWS or Google HSM) because PDF digital signature requires that, at least, the signer’s certificate is stored in the signed PDF file.

From AWS CloudHSM and Google KMS documentation, I don’t see any mention of X509 certificates, so the integration with GemBox.Pdf might have to be customized to dynamically create X509 certificates from the specified public key and other information that would be stored in the certificate generated with the System.Security.Cryptography.X509Certificates.CertificateRequest class.

Regards,
Mario

Hi Mario,

thank you very much for your detailed answer. This has helped me a lot!
I really appreciate that you have given so much effort to support me!