Skip to content

Instantly share code, notes, and snippets.

@jabez007
Created April 23, 2018 19:48
Show Gist options
  • Save jabez007/8e1faa49e43f8f63480f5d9f8b6fd18c to your computer and use it in GitHub Desktop.
Save jabez007/8e1faa49e43f8f63480f5d9f8b6fd18c to your computer and use it in GitHub Desktop.
Adding a digital and visible signature to a PDF
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace SignedReport
{
class SigningPdf : IDisposable
{
PdfReader reader = new PdfReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("SignedReport.Template.pdf"));
MemoryStream outputStream = new MemoryStream();
PdfStamper stamper;
public AttestationPdf()
{
stamper = PdfStamper.CreateSignature(reader, outputStream, '\0');
}
public void AddReport()
{
}
public void AddSignature()
{
AddDate();
ApplySignature();
stamper.Close();
}
private void AddDate()
{
stamper.AcroFields.SetField("Date", DateTime.Today.ToShortDateString());
}
private void ApplySignature()
{
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = "";
appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
appearance.Location = Environment.MachineName;
appearance.SignatureGraphic = Image.GetInstance(Assembly.GetExecutingAssembly().GetManifestResourceStream("SignedReport.signature.png"));
appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC;
appearance.SetVisibleSignature("Signature");
AsymmetricCipherKeyPair keyPair = null;
Oid signatureHashAlgorithm = null;
List<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
certStore.Open(OpenFlags.ReadOnly);
foreach (var cert in certStore.Certificates)
{
if (cert.HasPrivateKey)
{
// Get CN and Thumbprint from App.config
if (cert.SubjectName.Name.Replace(" ", "").Contains(@"CN=commonName"))
{
// make sure when the certificate was loaded into the certificate store
//that the allow export option was checked.
keyPair = DotNetUtilities.GetKeyPair(cert.PrivateKey);
signatureHashAlgorithm = cert.SignatureAlgorithm;
chain.Add(DotNetUtilities.FromX509Certificate(cert));
}
}
}
}
appearance.Certificate = chain[0];
appearance.SignDate = DateTime.Now;
IExternalSignature exSig = new PrivateKeySignature(keyPair.Private, "SHA-256");
MakeSignature.SignDetached(appearance, exSig, chain, null, null, null, 0, CryptoStandard.CMS);
}
public void SaveAs(string filePath)
{
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
byte[] output = outputStream.ToArray();
file.Write(output, 0, output.Length);
}
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
stamper.Dispose();
reader.Dispose();
outputStream.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~AttestationPdf() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment