简体   繁体   中英

Signing PDF document by certificate

Im trying digitaly sign PDF document with Syncfusion. (Library for generating pdf document)
Entire document, not just field. I don't know mutch about signing or certificates.
I know that certificate is type of HSM, so i used: Syncfusion - Externally sign a pdf document

It works on my development PC, but doesn't in production. Certificate is find, but at signing document it causes:

CryptographicException: Unknown error „-1073741823“ at System.Security.Cryptography.Pkcs.SignedCms.Sign(CmsSigner signer, Boolean silent)

My code:

using Syncfusion.Licensing;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;
using Syncfusion.Pdf.Parsing;
using Syncfusion.Pdf.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace SyncfusionTest3
{
    class Program
    {
        public static X509Certificate2 infoCertifikat = null;

        static void Main(string[] args)
        {


            var store = new System.Security.Cryptography.X509Certificates.X509Store(StoreLocation.LocalMachine);
            string thumbprint = "9F.."; //Production


            store.Open(OpenFlags.ReadOnly);

            foreach (var mCert in store.Certificates)
            {
                if (mCert.Thumbprint.ToUpper().Equals(thumbprint.ToUpper()))
                    infoCertifikat = mCert;
            }

            

            if (infoCertifikat == null)
            {
                Console.WriteLine("404 Certificate not found");
                Console.ReadKey();
                return;
            }


            string licenceKey = "LicenceKey";
            SyncfusionLicenseProvider.RegisterLicense(licenceKey);


            using (var pdfDoc = new PdfLoadedDocument("document.pdf"))
            {

                pdfDoc.DocumentInformation.Creator = "Me";
                pdfDoc.DocumentInformation.Author = "Naxi";


                PdfCertificate pdfCertificate = new PdfCertificate(infoCertifikat);

                //Normal signing
                //Syncfusion.Pdf.Security.PdfSignature signature1 = new Syncfusion.Pdf.Security.PdfSignature(pdfDoc, pdfDoc.Pages[0], pdfCertificate, "DigitalSign");

                //External signing becouse of HSM type of certificate
                Syncfusion.Pdf.Security.PdfSignature signature1 = new Syncfusion.Pdf.Security.PdfSignature(pdfDoc, pdfDoc.Pages[0], null, "DigitalSign");
                signature1.ComputeHash += Signature_ComputeHash1;

                


                signature1.Bounds = new System.Drawing.RectangleF((6 * 25.4f / 0.352777778f), (9.3f * 25.4f / 0.352777778f), 65, 25);
                signature1.ContactInfo = "Contact";
                signature1.LocationInfo = "World";
                signature1.Reason = "I want it";


                PdfStandardFont font = new PdfStandardFont(PdfFontFamily.Helvetica, 3.8f);
                float row_height = 4.2f;

                signature1.Appearance.Normal.Graphics.DrawString("Digitally Signed by " + signature1.ContactInfo, font, PdfBrushes.Black, 0, row_height * 1);
                signature1.Appearance.Normal.Graphics.DrawString("Reason: " + signature1.Reason, font, PdfBrushes.Black, 0, row_height * 2);
                signature1.Appearance.Normal.Graphics.DrawString("Location: " + signature1.LocationInfo, font, PdfBrushes.Black, 0, row_height * 3);
                signature1.Appearance.Normal.Graphics.DrawString((DateTime.Now).ToString(), font, PdfBrushes.Black, 0, row_height * 4);


                pdfDoc.Save("document_signed.pdf");
                pdfDoc.Close(true);
            }
        }


        

        private static void Signature_ComputeHash1(object sender, PdfSignatureEventArgs ars)
        {
            //Get the document bytes

            byte[] documentBytes = ars.Data;


            SignedCms signedCms = new SignedCms(new ContentInfo(documentBytes), detached: true);


            var cmsSigner = new CmsSigner(infoCertifikat);

            //Set the digest algorithm SHA256

            //cmsSigner.DigestAlgorithm = new Oid("1.3.6.1.4.1.311.10.3.12"); //Document signing – just tried

            //cmsSigner.DigestAlgorithm = new Oid("1.2.840.113549.1.1.11"); //SHA256RSA
            //cmsSigner.DigestAlgorithm = new Oid("1.2.840.113549.1.1.5"); //SHA1RSA
            //cmsSigner.DigestAlgorithm = new Oid("1.3.14.3.2.26"); //SHA1


            cmsSigner.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"); //SHA256
            


            cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly; //Without this it throws CryptographicException: A certificate chain could not be bulit to a trusted root authority. (only in production)

            signedCms.ComputeSignature(cmsSigner);
            

            //Embed the encoded digital signature to the PDF document

            ars.SignedData = signedCms.Encode();

        }
    }
}

I tried use different DigestAlgorithm. (commented in code) But i dont't know which i should use.
Im building it for Platform target x64 because without it it causes:

CryptographicException: The keyset is not defined. at System.Security.Cryptography.Pkcs.PkcsUtils.CreateSignerEncodeInfo(CmsSigner signer, Boolean silent, DafeCryptoProvHandle)

There is censored certificate used on production:

证书图片

My certificates on develop have Key Usage: Signing document,which is missing on production. Or Enhanced Key Usage is missing something?

Thank you for any sugesstion.

UPDATE: So, I made i little steps in different few ways which look hopefully, but not mutch.

  1. I tried Normal signing of Syncfusion and set CryptographicStandard.CADES
Syncfusion.Pdf.Security.PdfSignature signature1 = new Syncfusion.Pdf.Security.PdfSignature(pdfDoc, pdfDoc.Pages[0], pdfCertificate, "DigitalSign");
signature1.Settings.CryptographicStandard = CryptographicStandard.CADES;

Its make signed document and crash the program. Like without any exception.

  1. I looked on way, which was used some time ago and i find out, that it was signing with hashSHA1, RSA + PKCS#1.

So, i tried in external way use oid:

cmsSigner.DigestAlgorithm = new Oid("1, 3, 36, 3, 3, 1, 1"); //RSA + SHA1

And that causes: CryptographicsException: The object identifier is poorly formatted. at SignedCms.Sign(...)

  1. And another way Im triying is invating colleague, so we can suffer colletively.

I dont know what Im doing.

Update 2:

So, the right way is probably using external with SHA1. Signing document works, but when program ends, the program don't close like normal but stops working. The same thing do microsoft application certutil. After lists certificates it stops working.

This is new info about that certificate. Its in HSM provided by Luna.

================ Certificate 0 ================
Serial Number: ...
Issuer: ...
 NotBefore: ...
 NotAfter: ...
Subject: ...
Non-root Certificate
Cert Hash(sha1): 9f
  Key Container = ...
  Provider = Luna enhanced RSA and AES provider for Microsoft Windows
Private key is NOT exportable
ERROR: Could not verify certificate public key against private key
Revocation check skipped -- server offline
Certificate is valid

Make sure the certificate is installed in the correct store (you code shows StoreLocation.LocalMachine ). So let's first check if the certificate in the store is fine and the key is associated and accessible.

Run the following command to list and verify all certificates in the store:

certutil -verifystore MY

The output should show something like this:

================ Certificate X ================
Serial Number: ...
Issuer: ...
 NotBefore: ...
 NotAfter: ...
Subject: ...
Non-root Certificate
Cert Hash(sha1): ...
  Key Container = ...
  Unique container name: ...
  Provider = ...
Private key is NOT exportable
Signature test passed
...

This will show you the Private Key Association and its Provider and will create a signature to check if the key is accessible.

So ensure the permission to access the key is given for the user running the command, as well as your application. You might need to clarify this by reading the HSM user manual or contact someone the responsible person (in-house or the manufacturer support)

You SignedCms code looks good - for testing keep it as simple as possible (no digest algorithm) and step forward in small steps.

EDIT

Additionally, of curse, you need to have your certificate trusted. This means that the certificate trust chain is installed to the certificate store.

The certificates can be found here: http://crt.postsignum.cz/certifikaty_autorit.html

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