6

Background

I have been using iTextSharp for a short while now. I have created a pdf document with two signable PdfFormFields. If I open the pdf document I can manually sign each field manually. I want this to be done through iTextSharp.

I am currently retrieving the certificate from the X509Store. Up until this point, I could figure out.

Question

Can someone please show me how I can use this X509Certificate2 to sign an already existing signature AcroField.

enter image description here

References

The following references were visited and I couldn't find the answer I was looking for. Signing a pdf document

This link got me the closest I believe, but several of the lines used were invalid and I do not know if I can fix it by including some other libraries. https://www.dotnetportal.cz/blogy/15/Null-Reference-Exception/5250/Digitalni-podepisovani-PDF-souboru-v-C-cast-2

Prany
  • 2,078
  • 2
  • 13
  • 31
  • First of all, have you checked whether that form is an AcroForm or a XFA form? – mkl Jun 07 '18 at 10:20
  • It is an AcroForm, but only because I got the best examples for the AcroForm. – Stephan V.d Westhuizen Jun 07 '18 at 12:59
  • 1
    Have you tried something along the lines of [this answer](https://stackoverflow.com/a/13361647/1729265)? If that works, I'd suggest to use that with some improvements (in particular not to use SHA-1 but instead a member of the SHA-2 and SHA-3 families). – mkl Jul 02 '18 at 09:54
  • @StephanV.dWesthuizen did you get a solution to this? We are looking for a similar process. – cableload Oct 02 '18 at 17:58
  • 1
    @cableload I could not find a solution to this. We were using a third-party company to handle our signatures and wanted to sign our documents without having to use their external signing program. The project was time sensitive so I couldn't sit with this issue too long. I decided to use their API in our application instead of using the external program to sign the documents every time. Thank you for your help mkl. The company's name is DocuSign. It is not free though. Here is a link to their website: https://www.docusign.com. – Stephan V.d Westhuizen Oct 10 '18 at 05:19
  • @StephanV.dWesthuizen Thanks for the update. We will explore the docusign option as well. – cableload Oct 10 '18 at 14:44

1 Answers1

8

Everything you need:

appearance.SetVisibleSignature("---> ExistSignatureName <-----");
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);

Full Code:

private static void SignPdf(string filename, string folderPdf, string pathToNewSignFile, string pathToCerts, string nameCert, string passCert)
{      
    var pathToCert = GetFullNameFile(pathToCerts, nameCert); //Oh.. I did not know about the Path.Combine function.

    if (!File.Exists(pathToCert))
    {
        logger.Error("Certificate not exist " + pathToCert);
        return;
    }

    var pass = passCert.ToCharArray();

    FileStream fs;
    try
    {
        fs = new FileStream(pathToCert, FileMode.Open);
    }
    catch (Exception ex)
    {
        logger.Error(ex, "Could not open cert" + pathToCert);
        return;
    }

    var store = new Pkcs12Store(fs, pass);

    fs.Close();

    var alias = "";

    // searching for private key
    foreach (string al in store.Aliases)
        if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate) {
            alias = al;
            break;
        }

    var pk = store.GetKey(alias);

    ICollection<X509Certificate> chain = store.GetCertificateChain(alias).Select(c => c.Certificate).ToList();

    var parameters = pk.Key as RsaPrivateCrtKeyParameters;

    var pathPdf = GetFullNameFile(folderPdf, filename); //Oh.. I did not know about the Path.Combine function.

    var pathToSigPdf = GetFullNameFile(pathToNewSignFile, filename);

    if (!File.Exists(pathPdf))
    {
        logger.Error("Could not open file" + pathPdf + "  File not exist");
        return;
    }

    var reader = new PdfReader(pathPdf);


    FileStream fileStreamSigPdf;
    try
    {
        fileStreamSigPdf = new FileStream(pathToSigPdf, FileMode.Create);
    }
    catch (Exception ex)
    {
        logger.Error(ex, "Could not create file" + pathToSigPdf);
        return;
    }

    var stamper = PdfStamper.CreateSignature(reader, fileStreamSigPdf, '\0', null, true);

    var appearance = stamper.SignatureAppearance;
    appearance.Reason = "Утверждено";

    appearance.SetVisibleSignature("---> ExistSignatureName <-----");

    IExternalSignature pks = new PrivateKeySignature(parameters, DigestAlgorithms.SHA256);
    MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);

    fileStreamSigPdf.Close();
    reader.Close();
    stamper.Close();

    logger.Info("Signed successfully " + filename);
}

We have a web server in our company. 1. Get the hash field 2. With the help of the crypto plugin, we sign the hash 3. Insert the signature in the field

Step 1.

public string PrepareSignatureAndGetHash()
    {
        var hash = string.Empty;

        using (var reader = new PdfReader("PathTemplate"))
        {
            using (var fileStream = File.OpenWrite("PathToTemp"))
            {
                using (var stamper = PdfStamper.CreateSignature(reader, fileStream, '0', null, true))
                {
                    var signatureAppearance = stamper.SignatureAppearance;
                    signatureAppearance.SetVisibleSignature("ExistSignatureName");
                    IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
                    signatureAppearance.Reason = "Sig";
                    signatureAppearance.Layer2Text = "Super SIG";

                    signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;

                    MakeSignature.SignExternalContainer(signatureAppearance, external, 8192);


                    using (var contentStream = signatureAppearance.GetRangeStream())
                    {
                        hash = string.Join(string.Empty, SHA1.Create().ComputeHash(contentStream).Select(x => x.ToString("X2")));
                    }
                }
            }
        }

    return hash;
}

Step 2.

public void SigSignature(string base64String)
{
    using (var reader = new PdfReader("PathToTemp"))
    {
        using (var fileStream = File.OpenWrite("PathToSig"))
        {
            var byteSig = Convert.FromBase64String(base64String);
            IExternalSignatureContainer external = new MfuaExternalSignatureContainer(byteSig);

            MakeSignature.SignDeferred(reader, "ExistSignatureName", fileStream, external);
        }
    }
}

private class MfuaExternalSignatureContainer : IExternalSignatureContainer
{
    private readonly byte[] _signedBytes;

    public MfuaExternalSignatureContainer(byte[] signedBytes)
    {
        _signedBytes = signedBytes;
    }

    public byte[] Sign(Stream data)
    {
        return _signedBytes;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
    }
}
BabKafoX
  • 96
  • 1
  • 4