简体   繁体   English

为硬件令牌数字签名添加时间戳并添加 LTV 不起作用/抛出异常

[英]Add Timestamp for hardware token digital signature and adding LTV not working / throws exception

This is extended question from this question : add revocation detail in pdf while signing same这是这个问题的扩展问题: 在签名时在 pdf 中添加撤销详细信息

I have signed a pdf using itextsharp library and .net core (c#).我已经使用itextsharp库和 .net core (c#) 签署了一份 pdf。 after signing pdf I added LTV using AdobeLtvEnabling class from previous question.签署 pdf 后,我使用上一个问题中的AdobeLtvEnabling类添加了 LTV。 - Till here pdf is working fine. - 到这里 pdf 工作正常。

But when I am trying to embed timestamp in signature, it embeds but in AdobeLtvEnabling class's enable method in verification it throws exception :但是,当我尝试在签名中嵌入时间戳时,它嵌入但在AdobeLtvEnabling类的 enable 方法中进行验证时会引发异常:

Signer SHA256WITH1.2.840.10045.4.3.2 not recognised签名者 SHA256WITH1.2.840.10045.4.3.2 无法识别

Below is the code method for signing:下面是签名的代码方法:

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();
}

it uses AdobeLtvEnabling class from previous question I have used random free timestamp url in above code as my signing certificate does not have timestamp provisioned url in certificate details of cert or CA cert.它使用上一个问题中的AdobeLtvEnabling类我在上面的代码中使用了随机的免费时间戳网址,因为我的签名证书在证书或 CA 证书的证书详细信息中没有提供时间戳的网址。

This is the exported cer file without private key of cert这是没有cert私钥的导出cer文件

In above code if we remove below lines在上面的代码中,如果我们删除下面的行

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); 

with this line用这条线

MakeSignature.SignDetached(signatureAppearance, signature, chain, null, null, null, 0, CryptoStandard.CADES);

then it will generate signed pdf without timestamp.然后它将生成没有时间戳的签名pdf。 - which is ltv enabled and with green tick mark. - 启用了 ltv 并带有绿色勾号。

This is other signed pdf without timestamp using different cert token :- For this file timestamp is provisioned in CA cert which should be used while adding timestamp in signature.这是使用不同证书令牌的其他不带时间戳的签名 pdf :- 对于这个文件时间戳是在 CA 证书中提供的,应该在签名中添加时间戳时使用。 I don't have that token's exported DSC file.我没有该令牌的导出 DSC 文件。

Please guide me on below - 1.Why it is throwing exception and what it suggests?请在下面指导我 - 1.为什么它会抛出异常以及它的建议是什么? Is it correct way to add timestamp?添加时间戳是正确的方法吗? Can i use free open timestamping services if timestamping url is not present in CA cert.如果 CA 证书中不存在时间戳 url,我可以使用免费的开放时间戳服务吗? 2. If Timestamping URL is present in CA cert than how to access that url in object of code. 2. 如果时间戳 URL 存在于 CA 证书中,那么如何在代码对象中访问该 URL。 - We don't have such token here , which used in above signed pdf. - 我们这里没有这样的令牌,用于上面签名的pdf。

Thanks in advance.提前致谢。 please correct me if I am wrong anywhere.如果我在任何地方错了,请纠正我。

Update : exception : Signer SHA256WITH1.2.840.10045.4.3.2 not recognised.更新:异常:未识别签名者 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

I was trying with wrong pair of DSC (USB token) and timestamp URL.我尝试使用错误的 DSC(USB 令牌)和时间戳 URL 对。 That was the reson it was throwing exception to me while adding LTV.这就是它在添加 LTV 时向我抛出异常的原因。

Then I tried with actual global sign dsc and url embedded in it's property of x509 extension then it worked and I was able to sign PDF : zeta-uploader.com/browse/897639557然后我尝试使用实际的全局标志 dsc 和 url 嵌入它的 x509 扩展的属性然后它工作,我能够签署 PDF:zeta-uploader.com/browse/897639557

Reference Code for fetching timestamp 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"));
                    }
                }

Code for appending timestamp in make signature在 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);

In her own answer the OP has made clear that after switching to the correct key material for her use case the exception vanished.在她自己的回答中,OP 已经明确表示,在为她的用例切换到正确的密钥材料后,异常消失了。

This answer is about what to do if one gets the exception for the key material one does have to use.这个答案是关于如果一个人必须使用的关键材料的例外情况该怎么办。

The exception has message "Signer SHA256WITH1.2.840.10045.4.3.2 not recognised" and stack trace异常有消息“未识别签名者 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)

It occurs during the initialization of the iText class PdfPKCS7 which requests a signer with an invalid algorithm name, "SHA256WITH1.2.840.10045.4.3.2".它发生在 iText 类PdfPKCS7的初始化期间,该类请求使用无效算法名称“SHA256WITH1.2.840.10045.4.3.2”的签名者。 The OID 1.2.840.10045.4.3.2 stands for ecdsa-with-SHA256, and that illuminates the cause of the error here: The signature in question is an elliptic curve signature but iText 5.x does not support ECDSA algorithms. OID 1.2.840.10045.4.3.2 代表 ecdsa-with-SHA256,这说明了这里的错误原因:有问题的签名是椭圆曲线签名,但 iText 5.x 不支持 ECDSA 算法。

To LTV-enable such a signature using the AdobeLtvEnabling class (from this answer ) nonetheless, we, therefore, have to remove the use of PdfPKCS7 in it.尽管如此,要使用AdobeLtvEnabling类(来自此答案)启用 LTV 此类签名,我们必须删除其中对PdfPKCS7的使用。

We replace it by more generic BouncyCastle classes as follows, in the method enable replace the loop我们将其替换为更通用的 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));
}

by经过

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));
    }
}

Now a wider array of signature algorithms is supported, actually wider than is supported by Adobe Reader.现在支持更广泛的签名算法,实际上比 Adob​​e Reader 支持的范围更广。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM