我想在签署文档后返回启用了ltv的pdf。在诸如@mkl之类的高级开发人员的建议之前和之后,我都发布了类似的问题,我对代码进行了一些修改,但无法获得所需的结果。我已经尝试了一个多星期,我感到非常沮丧。请,如果有人愿意编辑代码或提供可能对我有帮助的建议,我将不胜感激。非常感谢。
所有方法都位于静态类“ SignMyPDF”中 这是我用来签名pdf的方法
public static byte[] Sign(byte[] document, X509Certificate2 certificate, ITSAClient tsaClient)
{
byte[] signedDocument = null;
IExternalSignature signature = new X509Certificate2Signature(certificate, "SHA-1");
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(certificate.RawData) };
PdfReader reader = new PdfReader(document);
MemoryStream ms = new MemoryStream();
PdfStamper st = PdfStamper.CreateSignature(reader, ms, '\0');
PdfSignatureAppearance sap = st.SignatureAppearance;
sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
sap.SignatureCreator = "NAME";
sap.Reason = "REASON";
sap.Contact = "CONTACT";
sap.Location = "LOCATION";
sap.SignDate = DateTime.Now;
RectangleF rectangle = new RectangleF(400.98139f, 54.88828f, 530, 84.88828f);
sap.Layer2Font = iTextSharp.text.FontFactory.GetFont(BaseFont.TIMES_ROMAN, BaseFont.CP1257, 7f);
sap.Layer2Font.Color = iTextSharp.text.BaseColor.RED;
sap.Layer2Text = string.Format("Signed for testing: {0}", DateTime.Now.ToString("dd.MM.yyyy."));
sap.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
sap.SetVisibleSignature(new iTextSharp.text.Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height), 1, null);
IOcspClient ocspClient = new OcspClientBouncyCastle();
ICrlClient crlClient = new CrlClientOnline();
List<ICrlClient> crlList = new List<ICrlClient>();
string[] crls = GetCrlDistributionPoints(certificate);
crlClient = new CrlClientOnline(crls);
crlList.Add(crlClient);
MakeSignature.SignDetached(sap, signature, chain, crlList, ocspClient, tsaClient, 0, CryptoStandard.CMS);
// ADD ltv to document
AddLtv(signedDocument, @"d:\test.pdf", ocspClient, crlClient, tsaClient);
st.Close();
ms.Flush();
signedDocument = ms.ToArray();
ms.Close();
reader.Close();
return signedDocument;
}
启用文档ltv的方法
public static void AddLtv(byte[] doc, string dest, IOcspClient ocsp, ICrlClient crl, ITSAClient tsa)
{
PdfReader r = new PdfReader(doc);
FileStream fos = new FileStream(dest, FileMode.Create);
PdfStamper stp = PdfStamper.CreateSignature(r, fos, '\0', null, true);
LtvVerification v = stp.LtvVerification;
AcroFields fields = stp.AcroFields;
List<string> names = fields.GetSignatureNames();
string sigName = names[names.Count - 1];
PdfPKCS7 pkcs7 = fields.VerifySignature(sigName);
if (pkcs7.IsTsp)
{
v.AddVerification(sigName, ocsp, crl,
LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
else
{
foreach (string name in names)
{
v.AddVerification(name, ocsp, crl,
LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
}
PdfSignatureAppearance sap = stp.SignatureAppearance;
LtvTimestamp.Timestamp(sap, tsa, null);
}
这些其他方法是从证书对象收集crl的助手
public static string[] GetCrlDistributionPoints(this X509Certificate2 certificate)
{
X509Extension ext = certificate.Extensions.Cast<X509Extension>().FirstOrDefault(
e => e.Oid.Value == "2.5.29.31");
if (ext == null || ext.RawData == null || ext.RawData.Length < 11)
return EmptyStrings;
int prev = -2;
List<string> items = new List<string>();
while (prev != -1 && ext.RawData.Length > prev + 1)
{
int next = IndexOf(ext.RawData, 0x86, prev == -2 ? 8 : prev + 1);
if (next == -1)
{
if (prev >= 0)
{
string item = Encoding.UTF8.GetString(ext.RawData, prev + 2, ext.RawData.Length - (prev + 2));
items.Add(item);
}
break;
}
if (prev >= 0 && next > prev)
{
string item = Encoding.UTF8.GetString(ext.RawData, prev + 2, next - (prev + 2));
items.Add(item);
}
prev = next;
}
return items.ToArray();
}
static int IndexOf(byte[] instance, byte item, int start)
{
for (int i = start, l = instance.Length; i < l; i++)
if (instance[i] == item)
return i;
return -1;
}
static string[] EmptyStrings = new string[0];
最后,这是调用sign方法的代码位于表单的加载处理程序中。这是活动中的所有内容。要签名的证书和文档存储在我的项目文件中。这就是为什么我使用“ path”变量。
private void Form1_Load(object sender, EventArgs e)
{
string path = Application.StartupPath;
path = path.Substring(0, path.LastIndexOf("\\"));
path = path.Substring(0, path.LastIndexOf("\\"));
byte[] document = System.IO.File.ReadAllBytes(path + "\\test.pdf");
X509Certificate2 certificate = new X509Certificate2(path + "\\cert.pfx", "misko123");
iTextSharp.text.pdf.security.ITSAClient tsaClient = new iTextSharp.text.pdf.security.TSAClientBouncyCastle("http://timestamp.comodoca.com");
byte[] signedDocument = SignMyPDF.Sign(document, certificate, tsaClient);
path = path + "\\test_signed.pdf";
System.IO.File.WriteAllBytes(path, signedDocument);
System.Diagnostics.Process.Start(path);
this.Close();
}
这里是指向我的证书和我要签名并启用ltv的文档的链接。
证书
https://drive.google.com/file/d/1P82Cc2sFN_z7fYImEvInWIRkD30OzPt6/view?usp=sharing
文档
https://drive.google.com/file/d/10_SqgmBrmzcQ4Motj6eVZkD0vb812HFY/view?usp=sharing
请帮助我。
答案 0 :(得分:0)
使用从my answer到your previous, more generic question的AdobeLtvEnabling
助手类,我可以使用证书和私钥对测试文档进行签名,然后LTV启用该签名。但是有两个限制:
CERTIFIED_NO_CHANGES_ALLOWED
一起使用,因此我不得不切换到CERTIFIED_FORM_FILLING
。除了认证级别的更改外,我可以使用previous question中的原始签名方法:
public byte[] Sign(byte[] document, X509Certificate2 certificate, ITSAClient tsaClient)
{
byte[] signedDocument = null;
IExternalSignature signature = new X509Certificate2Signature(certificate, "SHA-1");
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(certificate.RawData) };
PdfReader reader = new PdfReader(document);
MemoryStream ms = new MemoryStream();
PdfStamper st = PdfStamper.CreateSignature(reader, ms, '\0');
PdfSignatureAppearance sap = st.SignatureAppearance;
//sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING;
sap.SignatureCreator = "NAME";
sap.Reason = "REASON";
sap.Contact = "CONTACT";
sap.Location = "LOCATION";
sap.SignDate = DateTime.Now;
RectangleF rectangle = new RectangleF(400.98139f, 54.88828f, 530, 84.88828f);
sap.Layer2Font = iTextSharp.text.FontFactory.GetFont(BaseFont.TIMES_ROMAN, BaseFont.CP1257, 7f);
sap.Layer2Font.Color = iTextSharp.text.BaseColor.RED;
sap.Layer2Text = string.Format("Signed for testing: {0}", DateTime.Now.ToString("dd.MM.yyyy."));
sap.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
sap.SetVisibleSignature(new iTextSharp.text.Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height), 1, null);
MakeSignature.SignDetached(sap, signature, chain, null, null, tsaClient, 0, CryptoStandard.CMS);
st.Close();
ms.Flush();
signedDocument = ms.ToArray();
ms.Close();
reader.Close();
return signedDocument;
}
我的测试方法是:
using System;
using System.Drawing;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using NUnit.Framework;
using Org.BouncyCastle.Asn1.X509;
[...]
[Test]
public void testEnableKenJankasPdf()
{
byte[] document = File.ReadAllBytes(@"[...]\test.pdf");
X509Certificate2 certificate = new X509Certificate2(@"[...]\cert.pfx", "misko123");
X509Certificate2 extra1 = new X509Certificate2(@"[...]\AscertiaPublicCA1.crt");
X509Certificate2 extra2 = new X509Certificate2(@"[...]\AscertiaRootCA2.crt");
ITSAClient tsaClient = new TSAClientBouncyCastle("http://timestamp.comodoca.com");
byte[] signedDocument = Sign(document, certificate, tsaClient);
File.WriteAllBytes(@"[...]\Test_KenJanka-signed.pdf", signedDocument);
PdfReader reader = new PdfReader(signedDocument);
FileStream os = new FileStream(@"[...]\Test_KenJanka-enabled.pdf", FileMode.Create);
PdfStamper pdfStamper = new PdfStamper(reader, os, (char)0, true);
AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(pdfStamper);
AdobeLtvEnabling.extraCertificates.Add(new Org.BouncyCastle.X509.X509Certificate(X509CertificateStructure.GetInstance(extra1.GetRawCertData())));
AdobeLtvEnabling.extraCertificates.Add(new Org.BouncyCastle.X509.X509Certificate(X509CertificateStructure.GetInstance(extra2.GetRawCertData())));
IOcspClient ocsp = new OcspClientBouncyCastle();
ICrlClient crl = new CrlClientOnline();
adobeLtvEnabling.enable(ocsp, crl);
pdfStamper.Close();
}
我从以下位置下载了CA和根证书
- Ascertia根CA 2来自:http://www.ascertia.com/onlineCA/CA/AscertiaRootCA2.crt
- 来自以下位置的Ascertia CA 1:http://www.ascertia.com/onlineCA/CA/AscertiaPublicCA1.crt
如其web site所示。
当前Adobe Reader中的结果: