Я хочу вернуть PDF с поддержкой ltv после подписания документа.Я опубликовал аналогичный вопрос до и после предложений от продвинутых разработчиков, таких как @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);
}
Эти другие методы являются помощниками для сбора crls из объекта сертификата.
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];
И, наконец, этот код, вызывающий метод знака, находится в обработчике загрузки формы.,Вот и все на этом мероприятии.Сертификат и документ для подписи хранятся в файле моего проекта.Вот почему я использую переменную «путь».
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
Пожалуйста, мне нужна помощь.