using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using iTextSharp.text.pdf; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security;
namespace PdfSignerTest { class Program { static void Main(string[] args) { try { Console.WriteLine("Start"); string inputFileName = @"..\..\..\Report.pdf"; string outputFileName = @"..\..\..\Signed.pdf"; string timeStampUrl = "http://www.xxxx.com/timestamp.cgi"; using (FileStream inputPdfStream = new FileStream(inputFileName, FileMode.Open, FileAccess.Read)) { using (FileStream outputPdfStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write)) { X509Certificate2 card = SelectCertificate(); SignPdf(card, inputPdfStream, outputPdfStream, false, "Test Reason", "Test Location", "Test Contact", timeStampUrl, "teszt", "teszt"); } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } finally { Console.WriteLine("Done."); Console.ReadLine(); } } /// <summary> /// /// </summary> /// <param name="certificate">smart card certificate</param> /// <param name="inputPdfStream">input PDF</param> /// <param name="outputPdfStream">output PDF (signed)</param> /// <param name="append">append if <CODE>true</CODE> the signature and all the other content will be added as a new revision thus not invalidating existing signature</param> /// <param name="reason">Reason field of signature</param> /// <param name="location">Location field of signature</param> /// <param name="contact">Contact field of signature</param> /// <param name="tsaClientUrl">Timestamp server URL</param> /// <param name="tsaClientLogin">Login user for timestamp server (BASIC authentication)</param> /// <param name="tsaClientPwd">Login password for timestamp server</param> public static void SignPdf(X509Certificate2 certificate, Stream inputPdfStream, Stream outputPdfStream, bool append, string reason, string location, string contact, string tsaClientUrl, string tsaClientLogin, string tsaClientPwd) { // Building certificate chain for the OCSP verification X509Chain ch = new X509Chain(); ch.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; ch.Build(certificate); Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[ch.ChainElements.Count]; Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser(); int i = 0; foreach (X509ChainElement element in ch.ChainElements) { Org.BouncyCastle.X509.X509Certificate chainElement = cp.ReadCertificate(element.Certificate.RawData); chain[i] = chainElement; i++; } //Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser(); //Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(certificate.RawData) }; PdfReader reader = new PdfReader(inputPdfStream); PdfStamper st = PdfStamper.CreateSignature(reader, outputPdfStream, '\0', null, append); PdfSignatureAppearance sap = st.SignatureAppearance; sap.SetCrypto(null, chain, null, PdfSignatureAppearance.SELF_SIGNED); sap.Reason = reason; sap.Contact = contact; sap.Location = location; sap.SetVisibleSignature(new iTextSharp.text.Rectangle(50, 50, 200, 100), 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; Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>(); exc[PdfName.CONTENTS] = contentEstimated * 2 + 2; sap.PreClose(exc); PdfPKCS7 sgn = new PdfPKCS7(null, 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 (chain.Length >= 2) { String url = PdfPKCS7.GetOCSPURL(chain[0]); if (url != null && url.Length > 0) ocsp = new OcspClientBouncyCastle(chain[0], chain[1], url).GetEncoded(); //File.WriteAllBytes(@"..\..\..\ocsp.pdf", ocsp); } byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, cal, ocsp); // SHA1withRSA calculated by CAPI byte[] signedHashValue = SignSHA1withRSA(certificate, sh); sgn.SetExternalDigest(signedHashValue, hash, "RSA"); byte[] paddedSig = new byte[contentEstimated]; if (!string.IsNullOrEmpty(tsaClientUrl)) { TSAClientBouncyCastle tsc = new TSAClientBouncyCastle(tsaClientUrl, tsaClientLogin, tsaClientPwd); byte[] encodedSigTsa = sgn.GetEncodedPKCS7(hash, cal, tsc, ocsp); System.Array.Copy(encodedSigTsa, 0, paddedSig, 0, encodedSigTsa.Length); if (contentEstimated + 2 < encodedSigTsa.Length) throw new ApplicationException("Not enough space for signature"); } else { byte[] encodedSig = sgn.GetEncodedPKCS7(hash, cal, null, ocsp); System.Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); if (contentEstimated + 2 < encodedSig.Length) throw new ApplicationException("Not enough space for signature"); } PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); sap.Close(dic2); } public static byte[] SignSHA1withRSA(X509Certificate2 certificate, byte[] input) { const Int32 CRYPT_ACQUIRE_USE_PROV_INFO_FLAG = 0x00000002; const Int32 CRYPT_ACQUIRE_COMPARE_KEY_FLAG = 0x00000004; IntPtr privateKeyHandle = IntPtr.Zero; bool isCallerNeedFreeKeyHandle = false; IntPtr hashHandle = IntPtr.Zero; byte[] result = null; try { IntPtr cardHandle = certificate.Handle; Int32 pdwKeySpec = Crypto.AT_SIGNATURE; if (!Crypto.CryptAcquireCertificatePrivateKey(cardHandle, CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG, IntPtr.Zero, ref privateKeyHandle, ref pdwKeySpec, ref isCallerNeedFreeKeyHandle)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (!Crypto.CryptCreateHash(privateKeyHandle, Crypto.CALG_SHA1, IntPtr.Zero, 0, ref hashHandle)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } MemoryStream streamInput = new MemoryStream(input); byte[] buffer = new byte[4096]; while (true) { int read = streamInput.Read(buffer, 0, buffer.Length); if (read == 0) break; if (!Crypto.CryptHashData(hashHandle, buffer, read, 0)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } int pwdSigLen = 0; if (!Crypto.CryptSignHash(hashHandle, pdwKeySpec, null, 0, null, ref pwdSigLen)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } result = new byte[pwdSigLen]; if (!Crypto.CryptSignHash(hashHandle, pdwKeySpec, null, 0, result, ref pwdSigLen)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } // CAPI generated hash has a different indian order Array.Reverse(result); } finally { if (hashHandle != IntPtr.Zero) { if (!Crypto.CryptDestroyHash(hashHandle)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } if (isCallerNeedFreeKeyHandle && privateKeyHandle != IntPtr.Zero) { if (!Crypto.CryptReleaseContext(privateKeyHandle, 0)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } } return result; } public static X509Certificate2 SelectCertificate() { X509Store st = new X509Store(StoreName.My, StoreLocation.CurrentUser); st.Open(OpenFlags.ReadOnly); X509Certificate2Collection col = st.Certificates.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.NonRepudiation, true); X509Certificate2 card = null; X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(col, "Certificates", "Select one to sign", X509SelectionFlag.SingleSelection); if (sel.Count > 0) { X509Certificate2Enumerator en = sel.GetEnumerator(); en.MoveNext(); card = en.Current; } st.Close(); return card; } } } This is a working code, but unfortunatly copied from a Hungarian blog: http://gubus2.wordpress.com/2010/09/01/elektronikus-alairas-keszitese-pdf-allomanyra-smart-card-tamogatassal-net-alatt/ ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ _______________________________________________ iText-questions mailing list iText-questions@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/itext-questions iText(R) is a registered trademark of 1T3XT BVBA. Many questions posted to this list can (and will) be answered with a reference to the iText book: http://www.itextpdf.com/book/ Please check the keywords list before you ask for examples: http://itextpdf.com/themes/keywords.php