/** * Closes the document. No more content can be written after the * document is closed. * <p> * If closing a signed document with an external signature the closing must be done * in the <CODE>PdfSignatureAppearance</CODE> instance. * @throws DocumentException on error * @throws IOException on error */ public void Close() { if (!hasSignature) { stamper.Close(moreInfo); return; } sigApp.PreClose(); PdfSigGenericPKCS sig = sigApp.SigStandard; PdfLiteral lit = (PdfLiteral)sig.Get(PdfName.CONTENTS); int totalBuf = (lit.PosLength - 2) / 2; byte[] buf = new byte[8192]; int n; Stream inp = sigApp.RangeStream; while ((n = inp.Read(buf, 0, buf.Length)) > 0) { sig.Signer.Update(buf, 0, n); } buf = new byte[totalBuf]; byte[] bsig = sig.SignerContents; Array.Copy(bsig, 0, buf, 0, bsig.Length); PdfString str = new PdfString(buf); str.SetHexWriting(true); PdfDictionary dic = new PdfDictionary(); dic.Put(PdfName.CONTENTS, str); sigApp.Close(dic); stamper.reader.Close(); }
/** * This is the first method to be called when using external signatures. The general sequence is: * PreClose(), GetDocumentBytes() and Close(). * <p> * If calling PreClose() <B>dont't</B> call PdfStamper.Close(). * <p> * If using an external signature <CODE>exclusionSizes</CODE> must contain at least * the <CODE>PdfName.CONTENTS</CODE> key with the size that it will take in the * document. Note that due to the hex string coding this size should be * byte_size*2+2. * @param exclusionSizes a <CODE>Hashtable</CODE> with names and sizes to be excluded in the signature * calculation. The key is a <CODE>PdfName</CODE> and the value an * <CODE>Integer</CODE>. At least the <CODE>PdfName.CONTENTS</CODE> must be present * @throws IOException on error * @throws DocumentException on error */ public void PreClose(Dictionary<PdfName, int> exclusionSizes) { if (preClosed) throw new DocumentException(MessageLocalization.GetComposedMessage("document.already.pre.closed")); stamper.MergeVerification(); preClosed = true; AcroFields af = writer.AcroFields; String name = FieldName; bool fieldExists = !(IsInvisible() || IsNewField()); PdfIndirectReference refSig = writer.PdfIndirectReference; writer.SigFlags = 3; if (fieldExists) { PdfDictionary widget = af.GetFieldItem(name).GetWidget(0); writer.MarkUsed(widget); widget.Put(PdfName.P, writer.GetPageReference(Page)); widget.Put(PdfName.V, refSig); PdfObject obj = PdfReader.GetPdfObjectRelease(widget.Get(PdfName.F)); int flags = 0; if (obj != null && obj.IsNumber()) flags = ((PdfNumber)obj).IntValue; flags |= PdfAnnotation.FLAGS_LOCKED; widget.Put(PdfName.F, new PdfNumber(flags)); PdfDictionary ap = new PdfDictionary(); ap.Put(PdfName.N, GetAppearance().IndirectReference); widget.Put(PdfName.AP, ap); } else { PdfFormField sigField = PdfFormField.CreateSignature(writer); sigField.FieldName = name; sigField.Put(PdfName.V, refSig); sigField.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED; int pagen = Page; if (!IsInvisible()) sigField.SetWidget(PageRect, null); else sigField.SetWidget(new Rectangle(0, 0), null); sigField.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, GetAppearance()); sigField.Page = pagen; writer.AddAnnotation(sigField, pagen); } exclusionLocations = new Dictionary<PdfName,PdfLiteral>(); if (cryptoDictionary == null) { if (PdfName.ADOBE_PPKLITE.Equals(Filter)) sigStandard = new PdfSigGenericPKCS.PPKLite(); else if (PdfName.ADOBE_PPKMS.Equals(Filter)) sigStandard = new PdfSigGenericPKCS.PPKMS(); else if (PdfName.VERISIGN_PPKVS.Equals(Filter)) sigStandard = new PdfSigGenericPKCS.VeriSign(); else throw new ArgumentException(MessageLocalization.GetComposedMessage("unknown.filter.1", Filter)); sigStandard.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); if (Reason != null) sigStandard.Reason = Reason; if (Location != null) sigStandard.Location = Location; if (Contact != null) sigStandard.Contact = Contact; sigStandard.Put(PdfName.M, new PdfDate(SignDate)); sigStandard.SetSignInfo(PrivKey, CertChain, CrlList); PdfString contents = (PdfString)sigStandard.Get(PdfName.CONTENTS); PdfLiteral lit = new PdfLiteral((contents.ToString().Length + (PdfName.ADOBE_PPKLITE.Equals(Filter)?0:64)) * 2 + 2); exclusionLocations[PdfName.CONTENTS] = lit; sigStandard.Put(PdfName.CONTENTS, lit); lit = new PdfLiteral(80); exclusionLocations[PdfName.BYTERANGE] = lit; sigStandard.Put(PdfName.BYTERANGE, lit); if (certificationLevel > 0) AddDocMDP(sigStandard); if (signatureEvent != null) signatureEvent.GetSignatureDictionary(sigStandard); writer.AddToBody(sigStandard, refSig, false); } else { PdfLiteral lit = new PdfLiteral(80); exclusionLocations[PdfName.BYTERANGE] = lit; cryptoDictionary.Put(PdfName.BYTERANGE, lit); foreach (KeyValuePair<PdfName,int> entry in exclusionSizes) { PdfName key = entry.Key; int v = entry.Value; lit = new PdfLiteral(v); exclusionLocations[key] = lit; cryptoDictionary.Put(key, lit); } if (certificationLevel > 0) AddDocMDP(cryptoDictionary); if (signatureEvent != null) signatureEvent.GetSignatureDictionary(cryptoDictionary); writer.AddToBody(cryptoDictionary, refSig, false); } if (certificationLevel > 0) { // add DocMDP entry to root PdfDictionary docmdp = new PdfDictionary(); docmdp.Put(new PdfName("DocMDP"), refSig); writer.reader.Catalog.Put(new PdfName("Perms"), docmdp); } writer.Close(stamper.MoreInfo); range = new int[exclusionLocations.Count * 2]; int byteRangePosition = exclusionLocations[PdfName.BYTERANGE].Position; exclusionLocations.Remove(PdfName.BYTERANGE); int idx = 1; foreach (PdfLiteral lit in exclusionLocations.Values) { int n = lit.Position; range[idx++] = n; range[idx++] = lit.PosLength + n; } Array.Sort(range, 1, range.Length - 2); for (int k = 3; k < range.Length - 2; k += 2) range[k] -= range[k - 1]; if (tempFile == null) { bout = sigout.Buffer; boutLen = sigout.Size; range[range.Length - 1] = boutLen - range[range.Length - 2]; ByteBuffer bf = new ByteBuffer(); bf.Append('['); for (int k = 0; k < range.Length; ++k) bf.Append(range[k]).Append(' '); bf.Append(']'); Array.Copy(bf.Buffer, 0, bout, byteRangePosition, bf.Size); } else { try { raf = new FileStream(tempFile, FileMode.Open, FileAccess.ReadWrite); int boutLen = (int)raf.Length; range[range.Length - 1] = boutLen - range[range.Length - 2]; ByteBuffer bf = new ByteBuffer(); bf.Append('['); for (int k = 0; k < range.Length; ++k) bf.Append(range[k]).Append(' '); bf.Append(']'); raf.Seek(byteRangePosition, SeekOrigin.Begin); raf.Write(bf.Buffer, 0, bf.Size); } catch (IOException e) { try{raf.Close();}catch{} try{File.Delete(tempFile);}catch{} throw e; } } }