签名的 pdf 缺少来自时间戳服务器的时间戳
Signed pdf missing timestamp from timestamp server
我尝试使用外部网络服务对 pdf 进行数字签名。此 Web 服务包含用户证书,用户可以使用其凭据和一次性密码生成代码访问该证书。
旁注:Web 服务应该期望 pdf 摘要(哈希),但奇怪的是它接受整个文件。
总之实现如下:
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
// OTP = One Time Password code
public void SignPdf(string username, string password, string otp)
{
byte[] file = GetFileFromPath("D:\test.pdf");
var fieldName = "signatureField";
string tempFilePath = "D:\test1temp.pdf");
using (var pdfReader = new PdfReader(file))
{
using (var signedPdf = new FileStream(tempFilePath, FileMode.Create))
{
using (var pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '[=10=]', null, true);
{
// Prepare signature
PdfDate date = new PdfDate();
var fullSignDate = date.GetW3CDate();
var signDate = fullSignDate.Substring(0, fullSignDate.IndexOf("T"));
var signTime = fullSignDate.Substring(fullSignDate.IndexOf("T") + 1);
var signatureAppearance = pdfStamper.SignatureAppearance;
signatureAppearance.SetVisibleSignature(fieldName);
signatureAppearance.Layer2Text=($"Digitally signed by: Test User");
// Get font
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
signatureAppearance.CryptoDictionary = GetPdfSignature(signatureAppearance);
signatureAppearance.PreClose(new Dictionary<PdfName, int> { [PdfName.CONTENTS] = 8192 * 2 + 2 });
// Get file content as base64 string
var ms = new MemoryStream();
signatureAppearance.GetRangeStream().CopyTo(ms);
fileAsBase64 = ms.ToArray();
// Sign hash (the "hash" is the whole document)
signature = GetSignedHash(Convert.ToBase64String(fileAsBase64), username, password, otp);
if (signature != null)
{
EmbedSignatureToPdf(signatureAppearance, signatureWithTimeStamp);
success = true;
}
}
}
}
}
private static PdfDictionary GetPdfSignature(PdfSignatureAppearance sa)
{
return new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
{
Reason = sa.Reason,
Location = sa.Location,
SignatureCreator = sa.SignatureCreator,
Contact = sa.Contact,
Date = new PdfDate(sa.SignDate)
};
}
private byte[] GetSignedHash(string hash, string username, string password, string otp)
{
// Call external web service and get a the signed hash
}
private void EmbedSignatureToPdf(PdfSignatureAppearance signatureAppearance, byte[] signature)
{
var array = new byte[8192];
Array.Copy(signature, 0, array, 0, signature.Length);
var pdfDictionary = new PdfDictionary();
pdfDictionary.Put(PdfName.CONTENTS, new PdfString(array).SetHexWriting(true));
signatureAppearance.Close(pdfDictionary);
}
pdf 已成功签名,但使用 Adobe Reader 并检查签名字段似乎缺少受信任的时间戳,如图所示:
远程服务的响应似乎是一个签名对象,我只需要将其嵌入到 PDF 文件中即可。
我的问题是:由于我收到的签名不包含来自时间戳服务器的时间戳,此时我是否可以嵌入这样的时间戳,或者远程 Web 服务是否应该在将签名发送给我之前添加它?
谢谢!
Since the signature that I receive does not contain a timestamp from a timestamp server, can I embed such a timestamp at this point or should the remote web service add it before sending the signature to me?
这样的时间戳作为 unsigned 属性添加到签名容器中。因为它们没有签名,所以签名容器中的未签名属性可以在应用签名后更改,例如额外的可以取消添加。
因此,您自己尤其可以将时间戳添加到从您的服务中检索到的签名容器。
不过,根据您签名的性质,您可能必须增加在 pdf 中创建的占位符的大小,以便有足够的 space 用于附加时间戳。
我尝试使用外部网络服务对 pdf 进行数字签名。此 Web 服务包含用户证书,用户可以使用其凭据和一次性密码生成代码访问该证书。
旁注:Web 服务应该期望 pdf 摘要(哈希),但奇怪的是它接受整个文件。
总之实现如下:
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
// OTP = One Time Password code
public void SignPdf(string username, string password, string otp)
{
byte[] file = GetFileFromPath("D:\test.pdf");
var fieldName = "signatureField";
string tempFilePath = "D:\test1temp.pdf");
using (var pdfReader = new PdfReader(file))
{
using (var signedPdf = new FileStream(tempFilePath, FileMode.Create))
{
using (var pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '[=10=]', null, true);
{
// Prepare signature
PdfDate date = new PdfDate();
var fullSignDate = date.GetW3CDate();
var signDate = fullSignDate.Substring(0, fullSignDate.IndexOf("T"));
var signTime = fullSignDate.Substring(fullSignDate.IndexOf("T") + 1);
var signatureAppearance = pdfStamper.SignatureAppearance;
signatureAppearance.SetVisibleSignature(fieldName);
signatureAppearance.Layer2Text=($"Digitally signed by: Test User");
// Get font
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
signatureAppearance.CryptoDictionary = GetPdfSignature(signatureAppearance);
signatureAppearance.PreClose(new Dictionary<PdfName, int> { [PdfName.CONTENTS] = 8192 * 2 + 2 });
// Get file content as base64 string
var ms = new MemoryStream();
signatureAppearance.GetRangeStream().CopyTo(ms);
fileAsBase64 = ms.ToArray();
// Sign hash (the "hash" is the whole document)
signature = GetSignedHash(Convert.ToBase64String(fileAsBase64), username, password, otp);
if (signature != null)
{
EmbedSignatureToPdf(signatureAppearance, signatureWithTimeStamp);
success = true;
}
}
}
}
}
private static PdfDictionary GetPdfSignature(PdfSignatureAppearance sa)
{
return new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
{
Reason = sa.Reason,
Location = sa.Location,
SignatureCreator = sa.SignatureCreator,
Contact = sa.Contact,
Date = new PdfDate(sa.SignDate)
};
}
private byte[] GetSignedHash(string hash, string username, string password, string otp)
{
// Call external web service and get a the signed hash
}
private void EmbedSignatureToPdf(PdfSignatureAppearance signatureAppearance, byte[] signature)
{
var array = new byte[8192];
Array.Copy(signature, 0, array, 0, signature.Length);
var pdfDictionary = new PdfDictionary();
pdfDictionary.Put(PdfName.CONTENTS, new PdfString(array).SetHexWriting(true));
signatureAppearance.Close(pdfDictionary);
}
pdf 已成功签名,但使用 Adobe Reader 并检查签名字段似乎缺少受信任的时间戳,如图所示:
远程服务的响应似乎是一个签名对象,我只需要将其嵌入到 PDF 文件中即可。
我的问题是:由于我收到的签名不包含来自时间戳服务器的时间戳,此时我是否可以嵌入这样的时间戳,或者远程 Web 服务是否应该在将签名发送给我之前添加它?
谢谢!
Since the signature that I receive does not contain a timestamp from a timestamp server, can I embed such a timestamp at this point or should the remote web service add it before sending the signature to me?
这样的时间戳作为 unsigned 属性添加到签名容器中。因为它们没有签名,所以签名容器中的未签名属性可以在应用签名后更改,例如额外的可以取消添加。
因此,您自己尤其可以将时间戳添加到从您的服务中检索到的签名容器。
不过,根据您签名的性质,您可能必须增加在 pdf 中创建的占位符的大小,以便有足够的 space 用于附加时间戳。