[英]Add Timestamp for hardware token digital signature and adding LTV not working / throws exception
這是這個問題的擴展問題: 在簽名時在 pdf 中添加撤銷詳細信息
我已經使用itextsharp
庫和 .net core (c#) 簽署了一份 pdf。 簽署 pdf 后,我使用上一個問題中的AdobeLtvEnabling
類添加了 LTV。 - 到這里 pdf 工作正常。
但是,當我嘗試在簽名中嵌入時間戳時,它嵌入但在AdobeLtvEnabling
類的 enable 方法中進行驗證時會引發異常:
簽名者 SHA256WITH1.2.840.10045.4.3.2 無法識別
下面是簽名的代碼方法:
private static byte[] SignPdfWithCert(X509Certificate2 cert, byte[] SourcePdfBytes, Guid userId, string password, int xPlace, int yPlace, int width, int height, int pageNo, string dscPin, Org.BouncyCastle.X509.X509Certificate[] chain, string algorithm, string itemId, Stream imageStream, int MarginXForDSCToSearchText = 5, int MarginYForDSCToSearchText = 5)
{
var signature = new X509Certificate2Signature(cert, algorithm);
PdfReader pdfReader;
PdfReader.unethicalreading = true;
if (!string.IsNullOrEmpty(password))
pdfReader = new PdfReader(SourcePdfBytes, Encoding.ASCII.GetBytes(password));
else
pdfReader = new PdfReader(SourcePdfBytes);
MemoryStream signedPdf = new MemoryStream();
PdfStamper pdfStamper;
pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0', null, true); // Append new digital signature
if (string.IsNullOrEmpty(password) == false)
{
pdfStamper.SetEncryption(Encoding.ASCII.GetBytes(password), Encoding.ASCII.GetBytes(password), PdfWriter.AllowCopy, PdfWriter.ENCRYPTION_AES_256);
}
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
signatureAppearance.Location = cert.IssuerName.Name;
signatureAppearance.Acro6Layers = false;
signatureAppearance.Layer4Text = PdfSignatureAppearance.questionMark; //Property neeeds to be set for watermarking behind the signature which indicates signature status as per User's computer.
if (imageStream != null)
{
signatureAppearance.Layer2Text = "";
var image = iTextSharp.text.Image.GetInstance(imageStream);
signatureAppearance.SignatureGraphic = image;
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC;
}
else
{
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
}
signatureAppearance.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
signatureAppearance.SetVisibleSignature(new iTextSharp.text.Rectangle(xPlace, yPlace, xPlace + width, yPlace + height), pageNo, string.Concat(itemId, pageNo));
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
CspParameters cspp = new CspParameters();
cspp.KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName;
cspp.ProviderName = rsa.CspKeyContainerInfo.ProviderName;
// cspp.ProviderName = "Microsoft Smart Card Key Storage Provider";
cspp.ProviderType = rsa.CspKeyContainerInfo.ProviderType;
SecureString pwd = GetSecurePin(dscPin);
cspp.KeyPassword = pwd;
cspp.Flags = CspProviderFlags.NoPrompt;
try
{
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider(cspp);
}
catch
{
// ignored- pfx file
}
rsa.PersistKeyInCsp = true;
var url = "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23";
var tsc = new TSAClientBouncyCastle(url, null, null, 4096, "SHA-512");
MakeSignature.SignDetached(signatureAppearance, signature, chain, null, null, tsc, 0, CryptoStandard.CADES);
SourcePdfBytes = signedPdf.ToArray();
pdfStamper.Close();
var directory = System.AppDomain.CurrentDomain.BaseDirectory;
var finaltrustedSignedpdf = Path.Combine(directory, "TempFolder", Guid.NewGuid().ToString());
if (!Directory.Exists(finaltrustedSignedpdf))
{
Directory.CreateDirectory(finaltrustedSignedpdf);
}
finaltrustedSignedpdf = Path.Combine(finaltrustedSignedpdf, "LTVSignedpdf.pdf");
try
{
AddLtv(SourcePdfBytes, finaltrustedSignedpdf, new OcspClientBouncyCastle(), new CrlClientOnline());
var readbytes = File.ReadAllBytes(finaltrustedSignedpdf);
if (File.Exists(finaltrustedSignedpdf))
{
File.Delete(finaltrustedSignedpdf);
}
return readbytes;
}
catch
{
//Unable to add LTV due to no access on CRL URL
return SourcePdfBytes;
}
}
public static void AddLtv(byte[] src, string dest, IOcspClient ocsp, ICrlClient crl)
{
PdfReader reader = new PdfReader(src);
FileStream os = new FileStream(dest, FileMode.CreateNew);
PdfStamper pdfStamper = new PdfStamper(reader, os, (char)0, true);
AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(pdfStamper);
adobeLtvEnabling.enable(ocsp, crl);
pdfStamper.Close();
}
它使用上一個問題中的AdobeLtvEnabling
類我在上面的代碼中使用了隨機的免費時間戳網址,因為我的簽名證書在證書或 CA 證書的證書詳細信息中沒有提供時間戳的網址。
這是沒有cert私鑰的導出cer文件
在上面的代碼中,如果我們刪除下面的行
var url = "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23";
var tsc = new TSAClientBouncyCastle(url, null, null, 4096, "SHA-512");
MakeSignature.SignDetached(signatureAppearance, signature, chain, null, null, tsc, 0, CryptoStandard.CADES);
用這條線
MakeSignature.SignDetached(signatureAppearance, signature, chain, null, null, null, 0, CryptoStandard.CADES);
然后它將生成沒有時間戳的簽名pdf。 - 啟用了 ltv 並帶有綠色勾號。
這是使用不同證書令牌的其他不帶時間戳的簽名 pdf :- 對於這個文件時間戳是在 CA 證書中提供的,應該在簽名中添加時間戳時使用。 我沒有該令牌的導出 DSC 文件。
請在下面指導我 - 1.為什么它會拋出異常以及它的建議是什么? 添加時間戳是正確的方法嗎? 如果 CA 證書中不存在時間戳 url,我可以使用免費的開放時間戳服務嗎? 2. 如果時間戳 URL 存在於 CA 證書中,那么如何在代碼對象中訪問該 URL。 - 我們這里沒有這樣的令牌,用於上面簽名的pdf。
提前致謝。 如果我在任何地方錯了,請糾正我。
更新:異常:未識別簽名者 SHA256WITH1.2.840.10045.4.3.2。
堆棧跟蹤:
at Org.BouncyCastle.Security.SignerUtilities.GetSigner(String algorithm)
at iTextSharp.text.pdf.security.PdfPKCS7.InitSignature(AsymmetricKeyParameter key)
at iTextSharp.text.pdf.security.PdfPKCS7..ctor(Byte[] contentsKey, PdfName filterSubtype)
at iTextSharp.text.pdf.AcroFields.VerifySignature(String name)
at Cygnature.App.AdobeLtvEnabling.enable(IOcspClient ocspClient, ICrlClient crlClient) in D:\WorkSpace\Aug2019\Cygnature.Utility\CygnetGSPDSC\AdobeLTVEnabling.cs:line 43
at Cygnature.App.DigitalSignatureSigningService.AddLtv(Byte[] src, String dest, IOcspClient ocsp, ICrlClient crl) in D:\WorkSpace\Aug2019\Cygnature.Utility\CygnetGSPDSC\DigitalSignatureSigningService.cs:line 557
at Cygnature.App.DigitalSignatureSigningService.SignPdfWithCert(X509Certificate2 cert, Byte[] SourcePdfBytes, Guid userId, String password, Int32 xPlace, Int32 yPlace, Int32 width, Int32 height, Int32 pageNo, String dscPin, X509Certificate[] chain, String algorithm, String itemId, Stream imageStream, Int32 MarginXForDSCToSearchText, Int32 MarginYForDSCToSearchText) in D:\WorkSpace\Aug2019\Cygnature.Utility\CygnetGSPDSC\DigitalSignatureSigningService.cs:line 531
我嘗試使用錯誤的 DSC(USB 令牌)和時間戳 URL 對。 這就是它在添加 LTV 時向我拋出異常的原因。
然后我嘗試使用實際的全局標志 dsc 和 url 嵌入它的 x509 擴展的屬性然后它工作,我能夠簽署 PDF:zeta-uploader.com/browse/897639557
獲取時間戳網址的參考代碼:
X509Certificate2 cert = null;
X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
x509Store.Open(OpenFlags.ReadWrite);
//manually chose the certificate in the store
Selectcert: X509Certificate2Collection select = X509Certificate2UI.SelectFromCollection(x509Store.Certificates, null, null, X509SelectionFlag.SingleSelection);
if (select.Count > 0)
cert = select[0]; //This will get us the selected certificate in "cert" object
foreach (System.Security.Cryptography.X509Certificates.X509Extension extension in cert.Extensions)
{
if (extension.Oid.Value == "1.2.840.113583.1.1.9.1")
{
var ext = extension;
AsnEncodedData asndata = new AsnEncodedData(extension.Oid, extension.RawData);
var rawdata = asndata.RawData;
var val = Encoding.Default.GetString(rawdata);
var timestampUrl = TrimNonAscii(val);
timestampUrl = timestampUrl.Substring(timestampUrl.IndexOf("http"));
}
}
在 make 簽名中附加時間戳的代碼
var tsc = new TSAClientBouncyCastle(timestampUrl , null, null, 4096, "SHA-512");
//here timestamp url is fetched from above code
MakeSignature.SignDetached(signatureAppearance, signature, chain, null, null, tsc,
0, CryptoStandard.CADES);
在她自己的回答中,OP 已經明確表示,在為她的用例切換到正確的密鑰材料后,異常消失了。
這個答案是關於如果一個人必須使用的關鍵材料的例外情況該怎么辦。
異常有消息“未識別簽名者 SHA256WITH1.2.840.10045.4.3.2”和堆棧跟蹤
at Org.BouncyCastle.Security.SignerUtilities.GetSigner(String algorithm)
at iTextSharp.text.pdf.security.PdfPKCS7.InitSignature(AsymmetricKeyParameter key)
at iTextSharp.text.pdf.security.PdfPKCS7..ctor(Byte[] contentsKey, PdfName filterSubtype)
at iTextSharp.text.pdf.AcroFields.VerifySignature(String name)
它發生在 iText 類PdfPKCS7
的初始化期間,該類請求使用無效算法名稱“SHA256WITH1.2.840.10045.4.3.2”的簽名者。 OID 1.2.840.10045.4.3.2 代表 ecdsa-with-SHA256,這說明了這里的錯誤原因:有問題的簽名是橢圓曲線簽名,但 iText 5.x 不支持 ECDSA 算法。
盡管如此,要使用AdobeLtvEnabling
類(來自此答案)啟用 LTV 此類簽名,我們必須刪除其中對PdfPKCS7
的使用。
我們將其替換為更通用的 BouncyCastle 類,如下所示,在方法enable
替換循環
List<String> names = fields.GetSignatureNames();
foreach (String name in names)
{
PdfPKCS7 pdfPKCS7 = fields.VerifySignature(name);
PdfDictionary signatureDictionary = fields.GetSignatureDictionary(name);
X509Certificate certificate = pdfPKCS7.SigningCertificate;
addLtvForChain(certificate, ocspClient, crlClient, getSignatureHashKey(signatureDictionary, encrypted));
}
經過
List<String> names = fields.GetSignatureNames();
foreach (String name in names)
{
PdfDictionary signatureDictionary = fields.GetSignatureDictionary(name);
PdfString contents = signatureDictionary.GetAsString(PdfName.CONTENTS);
CmsSignedData signedData = new CmsSignedData(contents.GetOriginalBytes());
IX509Store certs = signedData.GetCertificates("COLLECTION");
foreach (SignerInformation signerInformation in signedData.GetSignerInfos().GetSigners())
{
ArrayList certList = new ArrayList(certs.GetMatches(signerInformation.SignerID));
X509Certificate certificate = (X509Certificate)certList[0];
addLtvForChain(certificate, ocspClient, crlClient, getSignatureHashKey(signatureDictionary, encrypted));
}
}
現在支持更廣泛的簽名算法,實際上比 Adobe Reader 支持的范圍更廣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.