0

enter image description hereI have SignedHash and certificate to sign the pdf file. The Signedhash and Certificate both received through external services. How to embed SignedHash to the PDF and then verify it with certificate using C#?

// Here we are using Itextsharp

    public static void SignDoc(string inputFilePath, string outputFilePath)
            {
// Open pdf
                using (PdfReader reader = new PdfReader(inputFilePath))
                {
                    using (MemoryStream ms = new MemoryStream())
                    {     
//Code to add new sig appearance           
    BaseFont helvetica = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, BaseFont.EMBEDDED);
                        Font font = new Font(helvetica, 12, iTextSharp.text.Font.NORMAL);                 
                        PdfStamper stamper = PdfStamper.CreateSignature(reader, ms, '\0');                  
                        PdfSignatureAppearance sap = stamper.SignatureAppearance;
                        sap.Reason = "";
                        sap.Location = "";
                        sap.Contact = "";
                        sap.Layer2Font = font;
// Setting up Visible Sig
             sap.SetVisibleSignature(new iTextSharp.text.Rectangle(415, 100, 585, 40), 1, null);
                var dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
                        dic.Reason = sap.Reason;
                        dic.Location = sap.Location;
                        dic.Contact = sap.Contact;
                        dic.Date = new PdfDate(sap.SignDate);
                        sap.CryptoDictionary = dic;
                        Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>();
                        exc.Add(PdfName.CONTENTS, (int)(8192 * 2 + 2));
                        sap.PreClose(exc);
                        Stream data = sap.GetRangeStream();
                        //Extract the bytes that need to be signed
                        // Creating hash of pdf with signature appearance
                        byte[] hash = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256); 

// Calling third party digidenty service for Cert as well as SignHash
    var signedDocResp = SignUtility.GetSignHashAndCertificate(BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant());
                        X509Certificate2 cert2 = new X509Certificate2(Encoding.Unicode.GetBytes(signedDocResp.Certificate));
                        var cert = new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(cert2.GetRawCertData());
                        var chain = new List<Org.BouncyCastle.X509.X509Certificate>() { cert };
                       PdfPKCS7 sgn = new PdfPKCS7(null, chain, DigestAlgorithms.SHA256, false);
    byte[] sh = sgn.getAuthenticatedAttributeBytes(Encoding.Unicode.GetBytes(signedDocResp.SignedHash), null, null, CryptoStandard.CMS);
                        sgn.SetExternalDigest(Encoding.Unicode.GetBytes(signedDocResp.SignedHash), null, "RSA");
             byte[] encodedSig = sgn.GetEncodedPKCS7(sh, null, null, null, CryptoStandard.CMS);
                        byte[] paddedSig = new byte[8192];
                        encodedSig.CopyTo(paddedSig, 0);
                        PdfDictionary dic2 = new PdfDictionary();
                        dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
                        sap.Close(dic2);
                        byte[] signed = ms.ToArray();              
                        File.WriteAllBytes(outputFilePath, signed);
                    }
                }
            }
  • You have tagged your question [tag:pdfbox] and [tag:c#] - how are you using this Java library from C#? You mention that you receive the signed hash and the certificate through external services. Do those services use the Cloud Signature Consortium (CSC) API? If not, which API then? – mkl Aug 03 '22 at 18:06
  • @mkl I have used IKVM to convet pdfbox into .net dll. I am sending pdf file hash to external service as input and received signhash as well as certificate in the form of string. Now the issue is How would I sign the document with the outputs? – Rajendra Mote Sep 07 '22 at 20:43
  • Which PDFBox version do you use? (The last time I heard IKVM being used with PDFBox was with some 1.8.x version.) And which hash have you signed? Have you followed some signing example code? – mkl Sep 08 '22 at 06:39
  • I am following https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature2.java – Rajendra Mote Sep 08 '22 at 06:47
  • As you are pointing to a signing example from the current PDFBox development branch (towards version 3), may I assume you are using a PDFBox version from the version 3 previews and alphas? – mkl Sep 08 '22 at 11:15
  • That being said, as you're following [CreateVisibleSignature2](https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature2.java), the actual CMS signature container is created in the [method `sign` inherited from the base class `CreateSignatureBase`](https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java#L133). So, that's the method which you have to change to create a CMS signature of the data in the stream argument using your external signing service. – mkl Sep 08 '22 at 11:27
  • @mkl , I have updated the question, I am using different approach using itextsharp. And added code in description. Now the error is ,"signature is invalid the document has been altered or corrupted since the signature was applied in itextsharp" – Rajendra Mote Sep 08 '22 at 12:44
  • First of all, since you switched to an iTextSharp based approach, you should change the tags of your question accordingly. And considering your new approach: Since some 5.3.x version iTextSharp has been offering a new, higher level signature API. If possible, you should upgrade. Furthermore, in your current code the `Encoding.Unicode.GetBytes` conversions look fishy. The one for the certificate _might_ be ok if the certificate is given in PEM format, but the one for the signed hash makes no sense. Also `sgn.getAuthenticatedAttributeBytes` and `sgn.GetEncodedPKCS7` calls don't match. – mkl Sep 08 '22 at 15:11
  • Hi @mkl, Can you please elaborate how can I use my external signing service to generate a signed pdf using PDFBox. I already have the certificate chain and signed hash generated from my CSC Remote Signer Service. How should I change the `sign` method to get a signed PDF. I tried my luck but not successful. I don't have the private key, since certificate is generated by CSC only. – Himanshu Jindal Feb 22 '23 at 11:10
  • @HimanshuJindal *"Can you please elaborate how can I use my external signing service to generate a signed pdf using PDFBox. I already have the certificate chain and signed hash generated from my CSC Remote Signer Service. How should I change the sign method to get a signed PDF. "* - Does [this answer](https://stackoverflow.com/a/75530257/1729265) help? – mkl Feb 22 '23 at 11:39
  • Thanks @mkl for the solution, I followed the same steps as given in your solution. I am still getting `Document has been altered or corrupted since it was signed`. Is it happening because we are again signing(using ContentSigner) the already signed hash (Signed by CSC)? – Himanshu Jindal Feb 23 '23 at 10:14
  • *"I am still getting `Document has been altered or corrupted since it was signed`"* - then please provide more information. Create a question focused on your issue including your pivotal code and example PDFs. – mkl Feb 23 '23 at 14:39
  • @mkl, It worked now. I was creating the unsigned hash outside of ContentSigner. Now I moved it inside ContentSigner, it is working fine. Thank you so much for help. One minor question though, I noticed that we are sending entire document hash, should not we exclude `hexadecimal string in contents section` before calculating hash? – Himanshu Jindal Feb 23 '23 at 15:12
  • @HimanshuJindal *"One minor question though, I noticed that we are sending entire document hash, should not we exclude `hexadecimal string in contents section before calculating hash?`"* - If it works now, you do exclude it. E.g. `externalSigning.getContent()` implicitly excludes it. – mkl Feb 23 '23 at 21:15

1 Answers1

0

There are multiple pdf libraries for C# (core or otherwise that can help you with that).

Example by IronPDF (paid for production/free for development)

// PM> Install-Package IronPdf
using IronPdf;
 
// Cryptographically sign an existing PDF in 1 line of code!
new IronPdf.Signing.PdfSignature("Iron.p12", "123456").SignPdfFile("any.pdf");
 
 
/***** Advanced example for more control *****/
 
// Step 1. Create a PDF
var Renderer = new IronPdf.ChromePdfRenderer();
using PdfDocument doc = Renderer.RenderHtmlAsPdf("<h1>Testing 2048 bit digital security</h1>");
 
// Step 2. Create a Signature.
// You may create a .pfx or .p12 PDF signing certificate using Adobe Acrobat Reader. 
// Read: https://helpx.adobe.com/acrobat/using/digital-ids.html
 
var signature = new IronPdf.Signing.PdfSignature("Iron.pfx", "123456");
 
// Step 3. Optional signing options and a handwritten signature graphic
signature.SigningContact = "support@ironsoftware.com";
signature.SigningLocation = "Chicago, USA";
signature.SigningReason = "To show how to sign a PDF";
signature.LoadSignatureImageFromFile("handwriting.png");
 
//Step 4. Sign the PDF with the PdfSignature. Multiple signing certificates may be used
doc.SignPdfWithDigitalSignature(signature);
 
//Step 4. The PDF is not signed until saved to file, steam or byte array.
doc.SaveAs("signed.pdf");

Example by iTextSharp (free) - Adding a Digital signature to a PDF with iTextSharp

More options here. All libraries that sign, also have a method to validate. Just check the documentation.

Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
  • The OP said *"The Signedhash and Certificate both received through external services."* I think this means that he does not use a pfx/p12 file as your code assumes but some signing service with hitherto unknown properties... – mkl Aug 03 '22 at 18:01
  • That's true mkl. I m not using pfx. – Rajendra Mote Aug 08 '22 at 08:57
  • @mkl I have used IKVM to convet pdfbox into .net dll. I am sending pdf file hash to external service as input and received signhash as well as certificate in the form of string. Now the issue is How would I sign the document with the outputs? – Rajendra Mote Sep 07 '22 at 20:43