为硬件令牌数字签名添加时间戳,并添加LTV不起作用/引发异常 [英] Add Timestamp for hardware token digital signature and adding LTV not working / throws exception

查看:129
本文介绍了为硬件令牌数字签名添加时间戳,并添加LTV不起作用/引发异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是此问题的扩展问题:在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类 我在上面的代码中使用了随机的免费时间戳URL,因为我的签名证书在cert或CA cert的证书详细信息中没有提供时间戳的url.

这是导出的 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 ,没有使用不同证书令牌的时间戳:-为此文件 timestamp是在CA证书中设置的,应在签名中添加时间戳时使用.我没有该令牌的导出DSC文件.

请在下面指导我- 1.为什么会引发异常及其提示?添加时间戳是正确的方法吗?如果CA证书中没有时间戳URL,我可以使用免费的开放时间戳服务吗? 2.如果CA证书中存在时间戳记URL,则比在代码对象中访问该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

解决方案

在自己的回答中,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支持的更广泛.

This is extended question from this question : add revocation detail in pdf while signing same

I have signed a pdf using itextsharp library and .net core (c#). after signing pdf I added LTV using AdobeLtvEnabling class from previous question. - Till here pdf is working fine.

But when I am trying to embed timestamp in signature, it embeds but in AdobeLtvEnabling class's enable method in verification it throws exception :

Signer SHA256WITH1.2.840.10045.4.3.2 not recognised

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.

This is the exported cer file without private key of cert

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. - which is ltv enabled and with green tick mark.

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. I don't have that token's exported DSC file.

Please guide me on below - 1.Why it is throwing exception and what it suggests? Is it correct way to add timestamp? Can i use free open timestamping services if timestamping url is not present in CA cert. 2. If Timestamping URL is present in CA cert than how to access that url in object of code. - We don't have such token here , which used in above signed pdf.

Thanks in advance. please correct me if I am wrong anywhere.

Update : exception : Signer SHA256WITH1.2.840.10045.4.3.2 not recognised.

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

解决方案

In her own answer the OP has made clear that after switching to the correct key material for her use case the exception vanished.

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

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". 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.

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.

We replace it by more generic BouncyCastle classes as follows, in the method enable replace the loop

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.

这篇关于为硬件令牌数字签名添加时间戳,并添加LTV不起作用/引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆