How do I sign a PDF document using a certificate from the Windows Cert Store?

c#, certificate, itext, pdf, signing

Solution

X509Certificate cert = certCollection[0]; // Your code
X509Certificate2 signatureCert = new X509Certificate2(cert);

var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signatureCert.PrivateKey).Private;

If you have the pk, which can get as above, you create an IExternalSignature as follows:

IExternalSignature es = new PrivateKeySignature(pk, "SHA-256");

You may also find the following articles of use:

- https://www.simple-talk.com/dotnet/.net-framework/beginning-with-digital-signatures-in-.net-framework/

- http://msdn.microsoft.com/en-us/library/ms223098.aspx

Problem

I need to sign a PDF document using a certificate that exists in the Windows Certificate Store. I have been digging around all day trying to figure it out, and I am so close yet so far away. All that is missing is this: How do I get an IExternalSignature object to sign the PDF file with? Rahul Singla has written a beautiful example of how to sign a PDF document using the new iText 5.3.0 API - as long as you can access a .pfx file sitting around on your PC somewhere. There is a previous question on signing using a certificate from the Windows Cert Store, except it was using a version of the API where `SetCrypto` still exists, and the signature was apparently optional. In iText 5.3.0, the API has changed, and `SetCrypto` is no longer a thing. Here's what I have so far (comments added for posterity, since this might be the most complete and recent version of how to do this on the 'net): ``` using iTextSharp.text.pdf; using iTextSharp.text.pdf.security; using BcX509 = Org.BouncyCastle.X509; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Crypto; using DotNetUtils = Org.BouncyCastle.Security.DotNetUtilities; ... // Set up the PDF IO PdfReader reader = new PdfReader(@"some\dir\SomeTemplate.pdf"); PdfStamper stamper = PdfStamper.CreateSignature(reader, new FileStream(@"some\dir\SignedPdf.pdf", FileMode.Create), '\0'); PdfSignatureAppearance sap = stamper.SignatureAppearance; sap.Reason = "For no apparent raisin"; sap.Location = "..."; // Acquire certificate chain var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine); certStore.Open(OpenFlags.ReadOnly); X509CertificateCollection certCollection = certStore.Certificates.Find(X509FindType.FindBySubjectName, "My.Cert.Subject", true); X509Certificate cert = certCollection[0]; // iTextSharp needs this cert as a BouncyCastle X509 object; this converts it. BcX509.X509Certificate bcCert = DotNetUtils.FromX509Certificate(cert); var chain = new List<BcX509.X509Certificate> { bcCert }; certStore.Close(); // Ok, that's the certificate chain done. Now how do I get the PKS? IExternalSignature signature = null; /* ??? */ // Sign the PDF file and finish up. MakeSignature.SignDetached(sap, signature, chain, // the important stuff null, null, null, 0, CryptoStandard.CMS); stamper.Close(); ``` As you can see: I have everything but the signature, and I'm stumped as to how I should obtain it!

Original source