using System; using System.Collections.Generic; using System.Text; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.X509; using System.Collections; using Org.BouncyCastle.Pkcs; using iTextSharp.text.pdf; using System.IO; using iTextSharp.text.xml.xmp; using Org.BouncyCastle.Security; using System.Security.Cryptography.X509Certificates; namespace Sleis.Pdf { public class PdfSignatureMaker { public SimpleCert Cert { get; set; } public void Init() { if (Cert == null) { throw new ArgumentNullException("cert"); } } public string Sign(string input, PdfSignatureArgs args) { if (String.IsNullOrEmpty(input) || !File.Exists(input)) { throw new FileNotFoundException("Input does not exist"); } string output = Path.Combine(Path.GetDirectoryName(input), String.Format("{0}-Signed.pdf", Path.GetFileNameWithoutExtension(input))); PdfReader reader = new PdfReader(input); FileStream fs = new FileStream(output, FileMode.Create, FileAccess.Write); PdfStamper st = PdfStamper.CreateSignature(reader, fs, '\0', null, true); st.MoreInfo = args.GetAllArgs(); st.XmpMetadata = args.GetStreamedArgs(); PdfSignatureAppearance sap = st.SignatureAppearance; sap.SetCrypto(null, Cert.Chain, null, PdfSignatureAppearance.WINCER_SIGNED); sap.Reason = args.Reason; sap.Contact = args.Contact; sap.Location = args.Locality; sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; sap.Acro6Layers = true; sap.Layer2Text = String.Format( "SLEIS signed on: {0}. See document signature for details.", DateTime.Now.ToString()); iTextSharp.text.Rectangle rect = st.Reader.GetPageSize(1); sap.Image = iTextSharp.text.Image.GetInstance(args.Display.Background.File.FullName); sap.SignDate = DateTime.Now; sap.SetVisibleSignature(new iTextSharp.text.Rectangle(args.Display.Location.X, args.Display.Location.Y, args.Display.Location.X + args.Display.Size.Width, args.Display.Location.Y + args.Display.Size.Height), 1, null); PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, new PdfName("adbe.pkcs7.detached")); dic.Reason = sap.Reason; dic.Location = sap.Location; dic.Contact = sap.Contact; dic.Date = new PdfDate(sap.SignDate); sap.CryptoDictionary = dic; int contentEstimated = 15000; // Preallocate excluded byte-range for the signature content (hex encoded) Dictionary exc = new Dictionary(); exc[PdfName.CONTENTS] = contentEstimated * 2 + 2; sap.PreClose(exc); PdfPKCS7 sgn = new PdfPKCS7(Cert.Akp, Cert.Chain, null, "SHA1", false); IDigest messageDigest = DigestUtilities.GetDigest("SHA1"); Stream data = sap.RangeStream; byte[] buf = new byte[8192]; int n; while ((n = data.Read(buf, 0, buf.Length)) > 0) { messageDigest.BlockUpdate(buf, 0, n); } byte[] hash = new byte[messageDigest.GetDigestSize()]; messageDigest.DoFinal(hash, 0); DateTime cal = DateTime.Now; byte[] ocsp = null; if (Cert.Chain.Length >= 2) { String url = PdfPKCS7.GetOCSPURL(Cert.Chain[0]); if (url != null && url.Length > 0) { ocsp = new OcspClientBouncyCastle(Cert.Chain[0], Cert.Chain[1], url).GetEncoded(); } } byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, cal, ocsp); sgn.Update(sh, 0, sh.Length); byte[] paddedSig = new byte[contentEstimated]; byte[] encodedSig = sgn.GetEncodedPKCS7(hash, cal); System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); if (contentEstimated + 2 < encodedSig.Length) { throw new Exception("Not enough space for signature"); } PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); sap.Close(dic2); return output; } } }