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

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

这是这个问题的扩展问题:

我已经使用 itextsharp 库和 .net 核心 (c#) 签署了一个 pdf。 签署 pdf 后,我使用上一个问题中的 AdobeLtvEnabling class 添加了 LTV。 - 直到这里 pdf 工作正常。

但是当我试图在签名中嵌入时间戳时,它嵌入了但是在 AdobeLtvEnabling class 的验证启用方法中它抛出异常:

Signer SHA256WITH1.2.840.10045.4.3.2 not recognised

下面是签名的代码方法:

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, '[=10=]', 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 class 我在上面的代码中使用了随机免费时间戳 url,因为我的签名证书在证书或 CA 证书的证书详细信息中没有提供时间戳 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.Why 它抛出异常及其提示是什么?添加时间戳的正确方法吗?如果 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

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

  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 在她自己的回答中明确表示,在为她的用例切换到正确的密钥 material 后,异常消失了。

这个答案是关于如果一个人得到了一个必须使用的密钥 material 的异常该怎么办。

异常有消息 "Signer SHA256WITH1.2.840.10045.4.3.2 not recognised" 和堆栈跟踪

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 class PdfPKCS7 的初始化期间,它请求签名者使用无效的算法名称 "SHA256WITH1.2.840.10045.4.3.2"。 OID 1.2.840.10045.4.3.2 代表 ecdsa-with-SHA256,这说明了错误的原因:有问题的签名是椭圆曲线签名,但 iText 5.x 不支持 ECDSA 算法。

尽管如此,为了使用 AdobeLtvEnabling class(来自 )启用这样的签名,我们必须删除 PdfPKCS7 在它。

我们用更通用的BouncyCastle classes替换它如下,方法中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));
    }
}

现在支持更广泛的签名算法,实际上比 Adob​​e 支持的更广泛Reader。