这是一个我很难应对的场景。我们希望我们的供应商能够使用 LTV 签名签署 PDF 文档,这样文档的有效性就不会过期。我已经阅读了 Bruno Lowagie 的著作iText in Action(第 2 版)、他的白皮书PDF 文档的数字签名,并查看了 PAdES 配置文件(PDF 文档的数字签名)。
用户使用具有电子 ID 的手机签署文件。该程序基本上将哈希发送到第三方服务,该服务对其进行签名并发回给我们,我们使用该签名并将其放入 PDF 文件中。这很好用,但这个签名的有效期只有三年左右。
我们如何在收到并添加签名后向 PDF 添加 DSS 和时间戳,以使用 iText 使 PDF 符合 PAdES LTV-Profile。我已经看到很多添加签名以及向它们添加时间戳和 OSCP 信息的示例,但这并不完全相同。
下面是一些代码,展示了我们从 preSign 和 postSign 方法开始所做的事情。这可行,但是如果可能的话,我应该在哪里以及如何添加代码来添加 DSS 和时间戳信息:
/// <summary>
/// Creates signature infrastructure to use in the signing process. Start with calling this method in the signature process.
/// </summary>
/// <param name="inStream">Byte stream with the PDF document to be signed</param>
/// <param name="reason">The reason for the signing</param>
/// <param name="location">Signing location</param>
/// <returns>Returns a hash of the signed data</returns>
public void preSign(byte[] inStream, string reason, string location)
{
iTextSharp.text.Document document = new iTextSharp.text.Document();
// Lesum inn PDF skjalið sem á að undirrita inn í iText reader
PdfReader reader = new PdfReader(inStream);
reader.Appendable = true;
Rectangle pageSize = reader.GetPageSizeWithRotation(1);
// Tengjum output stream við iText stamper
_outstream = new MemoryStream();
PdfStamper stamper = PdfStamper.CreateSignature(reader, _outstream, '\0', null, true);
stamper.InsertPage(reader.NumberOfPages + 1, reader.GetPageSize(reader.NumberOfPages));
_sap = stamper.SignatureAppearance;
float llx = pageSize.Width/2 - 350/2;
float lly = pageSize.Height/2 - 150/2;
float urx = llx + 350;
float ury = lly + 150;
_sap.SetVisibleSignature(new iTextSharp.text.Rectangle(llx, lly, urx, ury), reader.NumberOfPages, null);
_sap.Reason = reason;
_sap.Location = location;
_transactionTime = DateTime.Now;
_sap.SignDate = _transactionTime;
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(AppDomain.CurrentDomain.BaseDirectory + "UndirskriftDemo.png");
img.ScaleToFit(new Rectangle(350, 50));
_sap.Image = img;
_sap.Layer2Font = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 10.0f, 0, iTextSharp.text.BaseColor.BLACK);
_sap.Layer2Text = _userFullName + " undirritaði skjalið\nmeð rafrænum hætti \nþann " + _transactionTime.ToString("dd.MM.yyyy") + "\nStaður: " + location;
_sap.LocationCaption = "Location caption";
_sap.Contact = "Contact";
_sap.ReasonCaption = "ReasonCaption";
_sap.Layer4Text = "Layer 4 text";
// Create signature infrastructure
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, 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;
Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>();
exc.Add(PdfName.CONTENTS, (15000 * 2) + 2); // TSA: Content estimated er 15000 í stað 8192
//string tsa_url = ConfigurationManager.AppSettings["TSA_Url"];
//TSAClientBouncyCastle tsc = new TSAClientBouncyCastle(tsa_url);
//LtvTimestamp.Timestamp(_sap, tsc, null); // This can not be called here as then an exception will be thrown.
_sap.PreClose(exc);
Stream data = _sap.GetRangeStream();
_hash = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA1);
}
然后postSign:
public void PostSign(byte[] signatureData)
{
PdfSignatureAppearance sap = _sap;
byte[] paddedSig = new byte[15000];
System.Array.Copy(signatureData, 0, paddedSig, 0, signatureData.Length);
PdfDictionary dic = new PdfDictionary();
dic.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
sap.Close(dic);
}
这些方法是这样调用的:
// Sign the document
SignatureHelper signatureHelper = new SignatureHelper(itemID, employeeItemID, oUser.UserName, oUser.FullName);
signatureHelper.preSign(pdfBytes, "Undirritun til að staðfesta uppruna", "Reykjavík");
byte[] signatureData = signatureHelper.SignFile(pdfBytes, phoneNumber, itemID);
signatureHelper.PostSign(signatureData);
ro.ByteStream = signatureHelper.OutStream;