这是该问题的扩展问题:add revocation detail in pdf while signing same
我已经使用itextsharp
库和.net核心(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
类我在上面的代码中使用了随机的免费时间戳URL,因为我的签名证书在cert或CA cert的证书详细信息中没有时间戳时间戳url。
这是导出的cer file,没有证书的私钥
如果删除以下行,则在上面的代码中
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并带有绿色勾号。
这是其他signed pdf,没有时间戳,但使用了不同的证书令牌:-对于此文件时间戳是在CA证书中提供的,应在签名中添加时间戳时使用。我没有该令牌的导出DSC文件。
请在下面指导我-1.为什么会引发异常及其提示?添加时间戳是否正确?如果CA证书中没有时间戳URL,我可以使用免费的开放时间戳服务吗?2.如果CA证书中存在时间戳记URL,则如何在代码对象中访问该URL。 -我们这里没有这样的令牌,该令牌已在上面签名的pdf中使用。
谢谢。如果我在任何地方错了,请纠正我。
更新:异常:签名人SHA256WITH1.2.840.10045.4.3.2无法识别。
Stacktrace:
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时让我感到异常的原因。
然后,我尝试在x509扩展名的属性中嵌入实际的全局符号dsc和url,然后它起作用了,我能够对PDF进行签名:zeta-uploader.com/browse/897639557
获取时间戳URL的参考代码:
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"));
}
}
在签名中附加时间戳的代码
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
类(来自this answer)启用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支持的更广泛。