Adding a Digital signature to a PDF with iTextSharp

Stephan V.d Westhuizen picture Stephan V.d Westhuizen · Jun 7, 2018 · Viewed 9.6k times · Source

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

Answer

BabKafoX picture BabKafoX · Feb 27, 2019

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)
    {
    }
}