问题
I'm using ITextSharp's
PdfStamper to fill in a pdf form.
This works for unprotected and password protected Pdfs, but certificate protected PDFs cause a null reference exception
when calling PdfStamper.Close()
.
Has anyone come across this before?
Example failing program:
using System.Security.Cryptography.X509Certificates;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using Org.BouncyCastle.Crypto;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace ITextError
{
class Program
{
static X509Certificate2 certificate = new X509Certificate2(@"certificate.pfx","password",X509KeyStorageFlags.Exportable);
static X509Certificate bouncyCertficate = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(certificate);
static AsymmetricCipherKeyPair keyPair = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(certificate.PrivateKey);
public static byte[] CreatePdf()
{
using (MemoryStream ms = new MemoryStream())
{
using (Document document = new Document())
{
var writer=PdfWriter.GetInstance(document, ms);
writer.SetEncryption(new X509Certificate[]{bouncyCertficate},
new int[]{PdfWriter.ALLOW_MODIFY_CONTENTS},
PdfWriter.STANDARD_ENCRYPTION_128
);
document.Open();
document.Add(new Paragraph("Hello World"));
}
return ms.ToArray();
}
}
public static byte[] StampPdf(byte[] src)
{
File.WriteAllBytes("tmp.pdf",src);
PdfReader reader = new PdfReader("tmp.pdf",bouncyCertficate,keyPair.Private);
using (MemoryStream ms = new MemoryStream())
{
using (PdfStamper stamper = new PdfStamper(reader, ms,reader.PdfVersion,true))
{
PdfContentByte canvas = stamper.GetOverContent(1);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, new Phrase("Hello people!"), 36, 540, 0);
stamper.Close();
}
return ms.ToArray();
}
}
static void Main(string[] args)
{
File.WriteAllBytes(@"output.pdf",StampPdf(CreatePdf()));
}
}
}
Exception stacktrace:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at iTextSharp.text.pdf.PdfEncryption.CreateInfoId(Byte[] id, Boolean modified)
at iTextSharp.text.pdf.PdfEncryption.GetFileID(Boolean modified)
at iTextSharp.text.pdf.PdfStamperImp.Close(PdfIndirectReference info, Int32 s kipInfo)
at iTextSharp.text.pdf.PdfStamperImp.Close(IDictionary`2 moreInfo)
at iTextSharp.text.pdf.PdfStamper.Close()
at ITextError.Program.StampPdf(Byte[] src) in Program.cs:line 45
at ITextError.Program.Main(String[] args) in Program.cs:line 53
Exception is only thrown if the stamper is opened in append mode. But not using append mode removes the original protection, which I need to preserve.
ITextSharp is version 5.5.4 from Nuget stable.
回答1:
This iText issue has been resolved in version 5.5.12.
The relevant git check-in is d9aede3 dated March 31st, 2017, and has the comment "Fix exception when signing a document that is encrypted with certificate. Suggested by https://github.com/MADzO". This "signing" actually is a special case of arbitrary stamping while keeping the certificate protection intact.
The fix was to add the original document ID of the loaded PDF to the PdfEncryption
object (which holds the encryption related information) in case of certificate encryption, too, not only in case of password encryption as before.
The PdfEncryption
class expects its documentID
member to be set as encrypted documents must have an ID. As that member was not set in the cases at hand, the NullReferenceException
occurred.
Tested with the current iTextSharp 5.5.14-SNAPSHOT development version. Verified by undoing and redoing the above-mentioned fix.
Tested using test data provided by user JC1001 in a comment to his question iTextSharp object reference error on PdfStamper for certificate-protected file.
来源:https://stackoverflow.com/questions/27897744/itextsharp-bug-null-reference-when-stamping-certificate-protected-pdf