Sign PDF with Azure Key Vault Non-Exportable Certificate

Mike 96 Reputation points
2021-06-25T17:44:46.687+00:00

Hi,

I am looking to sign a PDF using an AATL compliant certificate stored in Azure Key Vault. I am using Aspose PDF for my document creation and signing. It looks to me that they support signing as they support signing from the windows certificate store as seen in their documents sign-pdf-document-from-smart-card. Is there a way for me to retrieve the secret and key from Azure Key Vault (with the methods below) and build a X509 to pass to their method instead of loading from the key store?

https://myvault.vault.azure.net/keys/testSigning/{mycertid}
https://myvault.vault.azure.net/secrets/testSigning/{mycertid}

I can create an X509 from the secret, but when I add the key, Aspose throws an error saying the Private Key does not match.

Using document As New Document(sourcePath)

            Using signature As New PdfFileSignature(document)

                signature.BindPdf(document)

                Dim store As X509Store = New X509Store
                Dim data As Byte() = Convert.FromBase64String(secret)

                Dim cert As New X509Certificate2(data)
                Dim prov As RSACryptoServiceProvider = New RSACryptoServiceProvider() 
                key = Convert.ToBase64String(Encoding.Unicode.GetBytes(key))
                prov.FromXmlString("")
                cert.PrivateKey = prov

                Dim extSig As ExternalSignature = New ExternalSignature(cert)


                signature.Sign(1, True, New System.Drawing.Rectangle(300, 100, 400, 200), extSig)
                signature.Save(signedPath)

            End Using

        End Using

I know iText supports this, but I don't want to pay close to $10K a year for iText just to sign my documents.

Thanks,
Mike

Azure Key Vault
Azure Key Vault

An Azure service that is used to manage and protect cryptographic keys and other secrets used by cloud apps and services.


2 answers

Sort by: Newest
  1. Chinnu 0 Reputation points
    2023-03-06T09:01:26.82+00:00

    The Syncfusion PDF library external signing process can assist us in signing non-exportable (private key) certificates in Azure Key Vault. Please see the following information for reference.

    When using a non-exportable certificate, the corresponding secret will not include the private key component. Although we can retrieve and create an in-memory representation of the certificate, we cannot use its private key for signing. Instead, we require the public portion of the certificate and the Azure Key Vault to sign the PDF data. To accomplish this, we can use the IPdfExternalSigner API interface to create the external signing portion as shown below.

    internal class ExternalSigner : IPdfExternalSigner
    {
        public string HashAlgorithm => "SHA256";
        private CryptographyClient keyClient;
           
        public ExternalSigner(CryptographyClient client)
        {
            keyClient = client;            
        }
    
        public byte[] Sign(byte[] message, out byte[] timeStampResponse)
        {
            var digest = SHA256.Create().ComputeHash(message);
            timeStampResponse = null;
    
            return keyClient
                .SignAsync(
                    SignatureAlgorithm.RS256,
                    digest)
                .Result.Signature;
        }
    }
    
    

    To add an external signer, we need to provide the public portion of the certificate. We can obtain the public certificates using the following code.

    private X509Certificate2 GetPublicCertificate()
    {
        //Create certificate client.
        CertificateClient certificateClient = new CertificateClient(new Uri("https://keyvault23752.vault.azure.net/"), credential);
    
        //Get the certificate with public key. //TestCertificate123 - certificate name.
        KeyVaultCertificateWithPolicy certificate = certificateClient.GetCertificateAsync("TestCertificate123").Result;
                
        //Create and return the X509Certificate2.
        return new X509Certificate2(certificate.Cer);
    }
    
    

    If a certificate contains multiple certificates, such as a root, intermediate, and issuer certificate, the following code can be used to build the certificate chain.

    //Get the public certifiate.
    X509Certificate2 pubCertifciate = GetPublicCertificate();
    
    //Build the certificate chain.
    X509Chain chain = new X509Chain();
    chain.Build(pubCertifciate);
    
    List<X509Certificate2> certificates = new List<X509Certificate2>();
    for (int i = 0; i < chain.ChainElements.Count; i++)
    {
        certificates.Add(chain.ChainElements[i].Certificate);
    }
    
    

    With the assistance of external signing, we can use the following code to sign the PDF data.

    public ActionResult SignPdfWithNonExportableCertificate()
    {
    
        //Get the public certifiate.
        X509Certificate2 pubCertifciate = GetPublicCertificate();
    
        //Build the certificate chain.
        X509Chain chain = new X509Chain();           
        chain.Build(pubCertifciate);
    
        List<X509Certificate2> certificates = new List<X509Certificate2>();
        for (int i = 0; i < chain.ChainElements.Count; i++)
        {
            certificates.Add(chain.ChainElements[i].Certificate);
        }
    
        FileStream pdfFile = new FileStream(_hostingEnvironment.WebRootPath + "/Input.pdf", FileMode.Open);
    
        //Load the PDF document.
        PdfLoadedDocument loadedDocument = new PdfLoadedDocument(pdfFile);
    
        //Load the existing page.
        PdfLoadedPage? page = loadedDocument.Pages[0] as PdfLoadedPage;
    
        //Create a new PDF signature object.
        PdfSignature signature = new PdfSignature(loadedDocument, page!, null, "Sig1");
    
        signature.Bounds = new Syncfusion.Drawing.RectangleF(0, 0, 200, 100);            
    
        //Create CryptographyClient.
        CryptographyClient client = new CryptographyClient(new Uri("https://keyvault23752.vault.azure.net/keys/TestCertificate123/dbbd00926ef54d40931d3f5df84e223c"), credential);
    
        //Sing using external signer.
        signature.AddExternalSigner(new ExternalSigner(client), certificates, null);
    
        signature.Settings.DigestAlgorithm = DigestAlgorithm.SHA256;
    
        MemoryStream ms = new MemoryStream();
    
        //Save and close the document.
        loadedDocument.Save(ms);
    
        ms.Position = 0;
    
        loadedDocument.Close(true);
    
        return File(ms, "application/pdf", "SignedDocument.pdf");
    }
    
    

    For more information, please refer to the following user guide documentation.

    https://help.syncfusion.com/file-formats/pdf/working-with-digitalsignature#externally-sign-the-pdf-document-using-ipdfexternalsigner

    Was this answer helpful?

    0 comments No comments

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.

    1 deleted comment

    Comments have been turned off. Learn more

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.