While working on a project, we recently came across a requirement to be able to digitally sign pdf documents in C# code using a public/private key pair and later be able to verify the signature. Basically we were working on an online e-Tendering portal for a semi-government organization. The organization wanted to accept documents from its Vendors online through a portal and be able to verify that the documents indeed originated from a particular Vendor. I would not go into the entire workflow here which is a bit complex, for simplicity you can assume the organization had the public keys for Vendors already stored in a secure database.

We were supposed to develop an easy to use desktop application which would allow Vendors to sign their pdf documents intuitively before submitting them to the Institute. Simultaneously a module was supposed to created in the organization’s portal that would allow Vendors to upload such signed documents, which would be verified for their signatures before being forwarded to various departments for processing.

We had been using the PdfSharp library extensively for various projects (one of which involved some complex pdf manipulation) with very good results. So when I took up this task today morning, I first started browsing PdfSharp’s API in hope of finding the classes and methods needed to sign and verify pdf documents. But I was to be disappointed, as I neither found anything in the API nor googling revealed any such feature in Pdfsharp library.

But I discovered the iTextSharp library in my Googling session which seemed to provide this feature. I downloaded the latest version (5.3.2 at the time of writing this blog post) but browsing the API up-front was not very meaningful. I again turned to Google which threw up this and this link with code samples for signing documents using iTextSharp. The first of these links was in Java while the second was in .Net. As I started adapting the code from these links, I realized many of the classes and methods being invoked were not present in my version of itextsharp.dll assembly. Somehow I assembled code for signing the document which seemed to work fine. And the signature information was visible when opening the document in a PDF reader.

As I approched the next step of verifying the signature (with code adapted from here), I was unable to verify the signature successfully even after making numerous revisions to the code. And I was back to square zero, signing a document without being able to verify the signature was pretty much useless.

I again went back googling. It was pretty much clear to me at this moment that iTextSharp library had undergone some considerable changes, and I needed code samples that would work with its latest version. Some frantic searching finally brought me over to the online version of the second edition of “iText in Action” book and then to this page from Chapter 12 of this book. I was pretty much sure now I had found what I needed.

Although the code samples were in Java and some aspects of the API are different in its .Net port, I was able to adapt the code from there and have it work in C#.

Without more of this introduction, I would now allow you to get your hands dirty with the actual code for signing a document using iTextSharp 5.3.x in .Net:

 

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }/// <summary>
/// Signs a PDF document using iTextSharp library
/// </summary>
/// <param name=”sourceDocument”>The path of the source pdf document which is to be signed</param>
/// <param name=”destinationPath”>The path at which the signed pdf document should be generated</param>
/// <param name=”privateKeyStream”>A Stream containing the private/public key in .pfx format which would be used to sign the document</param>
/// <param name=”keyPassword”>The password for the private key</param>
/// <param name=”reason”>String describing the reason for signing, would be embedded as part of the signature</param>
/// <param name=”location”>Location where the document was signed, would be embedded as part of the signature</param>
public static void signPdfFile (string sourceDocument, string destinationPath, Stream privateKeyStream, string keyPassword, string reason, string location)
{
Pkcs12Store pk12=new Pkcs12Store(privateKeyStream, keyPassword.ToCharArray());
privateKeyStream.Dispose();

//then Iterate throught certificate entries to find the private key entry
string alias=null;
foreach (string tAlias in pk12.Aliases)
{
if (pk12.IsKeyEntry(tAlias))
{
alias = tAlias;
break;
}
}
var pk=pk12.GetKey(alias).Key;

// reader and stamper
PdfReader reader = new PdfReader(sourceDocument);
using (FileStream fout = new FileStream(destinationPath, FileMode.Create, FileAccess.ReadWrite))
{
using (PdfStamper stamper = PdfStamper.CreateSignature(reader, fout, ‘\0’))
{
// appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
//appearance.Image = new iTextSharp.text.pdf.PdfImage();
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(20, 10, 170, 60), 1, “Icsi-Vendor”);
// digital signature
IExternalSignature es = new PrivateKeySignature(pk, “SHA-256”);
MakeSignature.SignDetached(appearance, es, new X509Certificate[] { pk12.GetCertificate(alias).Certificate }, null, null, null, 0, CryptoStandard.CMS);

stamper.Close();
}
}
}{/syntaxhighlighter}

The VSDoc comments at the top of the function should pretty much explain everything about the input parameters of this method to be able to call it.

 

And here’s the counter-part, a method to verify the signature of a previously signed PDF document:

 

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }/// <summary>
/// Verifies the signature of a prevously signed PDF document using the specified public key
/// </summary>
/// <param name=”pdfFile”>a Previously signed pdf document</param>
/// <param name=”publicKeyStream”>Public key to be used to verify the signature in .cer format</param>
/// <exception cref=”System.InvalidOperationException”>Throw System.InvalidOperationException if the document is not signed or the signature could not be verified</exception>
public static void verifyPdfSignature (string pdfFile, Stream publicKeyStream)
{
var parser=new X509CertificateParser();
var certificate=parser.ReadCertificate(publicKeyStream);
publicKeyStream.Dispose();

PdfReader reader = new PdfReader(pdfFile);
AcroFields af = reader.AcroFields;
var names = af.GetSignatureNames();

if (names.Count == 0)
{
throw new InvalidOperationException(“No Signature present in pdf file.”);
}

foreach (string name in names)
{
if (!af.SignatureCoversWholeDocument(name))
{
throw new InvalidOperationException(string.Format(“The signature: {0} does not covers the whole document.”, name));
}

PdfPKCS7 pk = af.VerifySignature(name);
var cal = pk.SignDate;
var pkc = pk.Certificates;

if (!pk.Verify())
{
throw new InvalidOperationException(“The signature could not be verified.”);
}
if (!pk.VerifyTimestampImprint())
{
throw new InvalidOperationException(“The signature timestamp could not be verified.”);
}

Object[] fails = CertificateVerification.VerifyCertificates(pkc, new X509Certificate[] { certificate }, null, cal);
if (fails != null)
{
throw new InvalidOperationException(“The file is not signed using the specified key-pair.”);
}
}
}{/syntaxhighlighter}

Again the VSDoc comments should explain how to call this method.

This code was assembled quickly and can certainly be improved (e.g, allow multiple iterations of signing with different public keys and corresponding verification, use a custom image for signature). Nevertheless, it should provide a base for quickly starting to use .Net’s version of iTextsharp library and building from here. You would fine iText in Action book very helpful for real-world examples and explanation on how to use this library.