简体   繁体   中英

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

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

I was trying with wrong pair of DSC (USB token) and timestamp URL. That was the reson it was throwing exception to me while adding 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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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