An Azure service that is used to manage and protect cryptographic keys and other secrets used by cloud apps and services.
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.