[英]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.