public void Sign(PDFSignatureAP sigAP, bool encrypt, PDFEncryption enc) { byte[] ownerPassword = null; if (!string.IsNullOrEmpty(enc.OwnerPwd)) { ownerPassword = DocWriter.GetISOBytes(enc.OwnerPwd); } PdfReader reader = new PdfReader(this.inputPDF, ownerPassword); FileStream fs = new FileStream(this.outputPDF, FileMode.Create, FileAccess.Write); PdfStamper st; if (this.myCert == null) //No signature just write meta-data and quit { st = new PdfStamper(reader, fs); } else { st = PdfStamper.CreateSignature(reader, fs, '\0', null, sigAP.Multi); } if (encrypt && enc != null) { enc.Encrypt(st); } //st.SetEncryption(PdfWriter.STRENGTH128BITS, "user", "owner", PdfWriter.ALLOW_COPY); st.MoreInfo = this.metadata.getMetaData(); st.XmpMetadata = this.metadata.getStreamedMetaData(); if (this.myCert == null) //No signature just write meta-data and quit { st.Close(); return; } PdfSignatureAppearance sap = st.SignatureAppearance; //sap.SetCrypto(this.myCert.Akp, this.myCert.Chain, null, PdfSignatureAppearance.WINCER_SIGNED); sap.SetCrypto(null, this.myCert.Chain, null, PdfSignatureAppearance.SELF_SIGNED); sap.Reason = sigAP.SigReason; sap.Contact = sigAP.SigContact; sap.Location = sigAP.SigLocation; if (sigAP.Visible) { iTextSharp.text.Rectangle rect = st.Reader.GetPageSize(sigAP.Page); sap.Image = sigAP.RawData == null ? null : iTextSharp.text.Image.GetInstance(sigAP.RawData); sap.Layer2Text = sigAP.CustomText; sap.SetVisibleSignature(new iTextSharp.text.Rectangle(sigAP.SigX, sigAP.SigY, sigAP.SigX + sigAP.SigW, sigAP.SigY + sigAP.SigH), sigAP.Page, null); } // Remove yellow question mark (green check mark is still used though) //sap.GetLayer(1); // The first signature is a certification //if (!sigAP.Multi) //{ // //sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; // sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING; //} 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 <PdfName, int> exc = new Dictionary <PdfName, int>(); exc[PdfName.CONTENTS] = contentEstimated * 2 + 2; sap.PreClose(exc); PdfPKCS7 sgn = new PdfPKCS7(this.myCert.Akp, this.myCert.Chain, null, "SHA-256", false); IDigest messageDigest = DigestUtilities.GetDigest("SHA-256"); // change for itextsharp-all-5.2.1 Stream data = sap.GetRangeStream(); 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 (this.myCert.Chain.Length >= 2) { String url = PdfPKCS7.GetOCSPURL(this.myCert.Chain[0]); if (url != null && url.Length > 0) { //ocsp = new OcspClientBouncyCastle(this.myCert.Chain[0], this.myCert.Chain[1], url).GetEncoded(); // change for itextsharp-all-5.2.1 ocsp = new OcspClientBouncyCastle().GetEncoded(this.myCert.Chain[0], this.myCert.Chain[1], url); } } byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, cal, ocsp); sgn.Update(sh, 0, sh.Length); byte[] paddedSig = new byte[contentEstimated]; if (this.myCert.Tsc != null) { byte[] encodedSigTsa = sgn.GetEncodedPKCS7(hash, cal, this.myCert.Tsc, ocsp); System.Array.Copy(encodedSigTsa, 0, paddedSig, 0, encodedSigTsa.Length); if (contentEstimated + 2 < encodedSigTsa.Length) { throw new Exception("Not enough space for signature"); } } else { 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)); //// Lock all fields after signing (backport from iText 5.4.4) - wrong - doesn't work //PdfDictionary lockDic = new PdfDictionary(new PdfName("SigFieldLock")); //lockDic.Put(PdfName.ACTION, new PdfName("All")); //lockDic.Put(PdfName.P, new PdfNumber(1)); //dic2.Put(PdfName.LOCK, lockDic); sap.Close(dic2); //st.Close(); }
public void Sign(PDFSignatureAP sigAP, bool encrypt, PDFEncryption enc) { byte[] ownerPassword = null; if (!string.IsNullOrEmpty(enc.OwnerPwd)) { ownerPassword = DocWriter.GetISOBytes(enc.OwnerPwd); } PdfReader reader = new PdfReader(this.inputPDF, ownerPassword); FileStream fs = new FileStream(this.outputPDF, FileMode.Create, FileAccess.Write); PdfStamper st; if (this.myCert == null) //No signature just write meta-data and quit { st = new PdfStamper(reader, fs); } else { st = PdfStamper.CreateSignature(reader, fs, '\0', null, sigAP.Multi); } if (encrypt && enc != null) enc.Encrypt(st); //st.SetEncryption(PdfWriter.STRENGTH128BITS, "user", "owner", PdfWriter.ALLOW_COPY); st.MoreInfo = this.metadata.getMetaData(); st.XmpMetadata = this.metadata.getStreamedMetaData(); if (this.myCert == null) //No signature just write meta-data and quit { st.Close(); return; } PdfSignatureAppearance sap = st.SignatureAppearance; //sap.SetCrypto(this.myCert.Akp, this.myCert.Chain, null, PdfSignatureAppearance.WINCER_SIGNED); sap.SetCrypto(null, this.myCert.Chain, null, PdfSignatureAppearance.SELF_SIGNED); sap.Reason = sigAP.SigReason; sap.Contact = sigAP.SigContact; sap.Location = sigAP.SigLocation; if (sigAP.Visible) { iTextSharp.text.Rectangle rect = st.Reader.GetPageSize(sigAP.Page); sap.Image = sigAP.RawData == null ? null : iTextSharp.text.Image.GetInstance(sigAP.RawData); sap.Layer2Text = sigAP.CustomText; sap.SetVisibleSignature(new iTextSharp.text.Rectangle(sigAP.SigX, sigAP.SigY, sigAP.SigX + sigAP.SigW, sigAP.SigY + sigAP.SigH), sigAP.Page, null); } // Remove yellow question mark (green check mark is still used though) //sap.GetLayer(1); // The first signature is a certification //if (!sigAP.Multi) //{ // //sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; // sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING; //} 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<PdfName, int> exc = new Dictionary<PdfName, int>(); exc[PdfName.CONTENTS] = contentEstimated * 2 + 2; sap.PreClose(exc); PdfPKCS7 sgn = new PdfPKCS7(this.myCert.Akp, this.myCert.Chain, null, "SHA-256", false); IDigest messageDigest = DigestUtilities.GetDigest("SHA-256"); // change for itextsharp-all-5.2.1 Stream data = sap.GetRangeStream(); 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 (this.myCert.Chain.Length >= 2) { String url = PdfPKCS7.GetOCSPURL(this.myCert.Chain[0]); if (url != null && url.Length > 0) { //ocsp = new OcspClientBouncyCastle(this.myCert.Chain[0], this.myCert.Chain[1], url).GetEncoded(); // change for itextsharp-all-5.2.1 ocsp = new OcspClientBouncyCastle().GetEncoded(this.myCert.Chain[0], this.myCert.Chain[1], url); } } byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, cal, ocsp); sgn.Update(sh, 0, sh.Length); byte[] paddedSig = new byte[contentEstimated]; if (this.myCert.Tsc != null) { byte[] encodedSigTsa = sgn.GetEncodedPKCS7(hash, cal, this.myCert.Tsc, ocsp); System.Array.Copy(encodedSigTsa, 0, paddedSig, 0, encodedSigTsa.Length); if (contentEstimated + 2 < encodedSigTsa.Length) throw new Exception("Not enough space for signature"); } else { 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)); //// Lock all fields after signing (backport from iText 5.4.4) - wrong - doesn't work //PdfDictionary lockDic = new PdfDictionary(new PdfName("SigFieldLock")); //lockDic.Put(PdfName.ACTION, new PdfName("All")); //lockDic.Put(PdfName.P, new PdfNumber(1)); //dic2.Put(PdfName.LOCK, lockDic); sap.Close(dic2); //st.Close(); }
private void signWorker_DoWork(object sender, DoWorkEventArgs e) { Cert myCert = null; string certName = null; string tsaUrl = "http://timestamp.globalsign.com/scripts/timestamp.dll"; // null if unused X509Certificate2 certificateData = certificates[certificateComboSelectedIndex] as X509Certificate2; if (certificateData != null) { certName = ExtractDNField(certificateData.Subject, "CN"); if (certName == null) { certName = certificateData.Subject; // Use fallback } byte[] bytes = certificateData.Export(X509ContentType.Pfx, ""); myCert = new Cert(bytes, "", tsaUrl, "" /* TSA login */, "" /* TSA password */); } else { return; //myCert = new Cert(certificateTextBox.Text, certificatePwdBox.Text, tsaUrl, tsaLogin.Text, tsaPwd.Text); } if (reasonComboText == null) { reasonComboText = ""; } // Copy original to backup file, then sign that back to original file name string outputFile; bool outputFileIsTemporary = false; outputFile = Path.GetFileNameWithoutExtension(inputFileTextText) + ".unsigned" + Path.GetExtension(inputFileTextText); outputFile = Path.Combine(Path.GetDirectoryName(inputFileTextText), outputFile); string inputFile = outputFile; // Create a copy if it does not exist yet (keep original unsigned forever) if (!File.Exists(outputFile)) { File.Copy(inputFileTextText, outputFile); outputFile = inputFileTextText; } else { // We need a different temporary file inputFile = inputFileTextText; outputFile = Path.GetTempFileName(); outputFileIsTemporary = true; } // NOTES: // * Encryption can only be applied before any signatures exist, otherwise existing signatures are broken. // * Encryption requires a non-empty password set, or we'll get problems when opening next time. // * Permissions can only be set together with the encryption status. // => Permissions cannot be changed once a signature exists. // http://stackoverflow.com/q/20008256/143684 // TODO PDFEncryption pdfEnc = new PDFEncryption(); pdfEnc.UserPwd = ""; //pdfEnc.OwnerPwd = "1234"; pdfEnc.OwnerPwd = ""; pdfEnc.Encryption = true; // Use 128 bit instead of 40 bit, but still RC4 // Permissions explanation: http://www.pdflib.com/knowledge-base/pdf-security/permissions/ pdfEnc.Permissions.Add(permissionType.Copy); pdfEnc.Permissions.Add(permissionType.DegradedPrinting); pdfEnc.Permissions.Add(permissionType.Printing); pdfEnc.Permissions.Add(permissionType.ScreenReaders); //pdfEnc.Permissions.Add(permissionType.Assembly); pdfEnc.Permissions.Add(permissionType.FillIn); // Includes signing //pdfEnc.Permissions.Add(permissionType.ModifyAnnotation); //pdfEnc.Permissions.Add(permissionType.ModifyContent); // Sign document PDFSigner pdfs = new PDFSigner(inputFile, outputFile, myCert, metaData); PDFSignatureAP sigAp = new PDFSignatureAP(); sigAp.SigReason = reasonComboText; sigAp.SigContact = ""; sigAp.SigLocation = ""; sigAp.Visible = visibleSignatureCheckChecked; sigAp.Multi = existingSignatures; sigAp.Page = pageNumValue; sigAp.CustomText = ""; if (visibleSignatureCheckChecked) { if (showName) { if (showLabels) { sigAp.CustomText += "Digital signiert von "; } sigAp.CustomText += certName + "\n"; } if (showLocation) { string country = ExtractDNField(certificateData.Subject, "C"); string locality = ExtractDNField(certificateData.Subject, "L"); if (!string.IsNullOrEmpty(country) || !string.IsNullOrEmpty(locality)) { if (showLabels) { sigAp.CustomText += "Ort: "; } sigAp.CustomText += locality + (!string.IsNullOrEmpty(locality) && !string.IsNullOrEmpty(country) ? ", " : "") + country + "\n"; } } if (showReason) { if (showLabels) { sigAp.CustomText += "Grund: "; } sigAp.CustomText += reasonComboText + "\n"; } if (showDate) { if (showLabels) { sigAp.CustomText += "Datum: "; } sigAp.CustomText += DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss K") + "\n"; } sigAp.CustomText = sigAp.CustomText.TrimEnd(); if (showImage && signaturePictureImage != null) { using (MemoryStream ms = new MemoryStream()) { signaturePictureImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); sigAp.RawData = ms.ToArray(); } } sigAp.SigX = mm2pt(leftNumValue); sigAp.SigY = mm2pt(bottomNumValue); sigAp.SigW = mm2pt(widthNumValue); sigAp.SigH = mm2pt(heightNumValue); } // Encrypt only if no signatures exist. Later it won't work anymore because it'll // break the existing signatures. pdfs.Sign(sigAp, false /*!existingSignatures*/, pdfEnc); if (outputFileIsTemporary) { // Delete input file and replace with temp output File.Delete(inputFile); File.Move(outputFile, inputFile); } }