Skip to main content
Skip table of contents

Digital signatures - chapter 2

These examples were written in the context of Chapter 2 - "PDF and digital signatures" of the Digital Signatures for PDF documents eBook.


c2_01_signhelloworld

A simple example of adding a visible signature to a document:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C2_01_SignHelloWorld {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "hello_signed1.pdf",
            "hello_signed2.pdf",
            "hello_signed3.pdf",
            "hello_signed4.pdf"
    };

    public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard signatureType, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setReason(reason)
                .setLocation(location)

                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .setReuseAppearance(false)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");

        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, signatureType);
    }

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        C2_01_SignHelloWorld app = new C2_01_SignHelloWorld();
        app.sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
        app.sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA512, provider.getName(),
                PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
        app.sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
        app.sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.RIPEMD160, provider.getName(),
                PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_01_SignHelloWorld
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "hello_signed1.pdf",
            "hello_signed2.pdf",
            "hello_signed3.pdf",
            "hello_signed4.pdf"
        };

        public void Sign(String src, String dest, X509Certificate[] chain, ICipherParameters pk,
            String digestAlgorithm, PdfSigner.CryptoStandard subfilter, String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            Rectangle rect = new Rectangle(36, 648, 200, 100);
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance
                .SetReason(reason)
                .SetLocation(location)

                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .SetReuseAppearance(false)
                .SetPageRect(rect)
                .SetPageNumber(1);
            signer.SetFieldName("sig");

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            C2_01_SignHelloWorld app = new C2_01_SignHelloWorld();
            app.Sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
            app.Sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA512,
                PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
            app.Sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
            app.Sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.RIPEMD160,
                PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
        }
    }
}

c2_02_signhelloworldwithtempfile

Signing a document using a temporary file to avoid OutOfMemoryExceptions with large PDFs:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

public class C2_02_SignHelloWorldWithTempFile {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "hello_signed_with_temp.pdf"
    };

    public void sign(String src, String temp, String dest, Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);

        // Pass the temporary file's path to the PdfSigner constructor
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), temp, new StampingProperties());

        // Create the signature appearance
        Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setReason(reason)
                .setLocation(location)

                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .setReuseAppearance(false)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");

        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        new C2_02_SignHelloWorldWithTempFile().sign(SRC, DEST, DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Temp test", "Ghent");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_02_SignHelloWorldWithTempFile
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "hello_signed_with_temp.pdf"
        };

        public void Sign(String src, String tmp, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);

            // Pass the temporary file's path to the PdfSigner constructor
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), tmp,
                new StampingProperties());

            // Create the signature appearance
            Rectangle rect = new Rectangle(36, 648, 200, 100);
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance
                .SetReason(reason)
                .SetLocation(location)

                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .SetReuseAppearance(false)
                .SetPageRect(rect)
                .SetPageNumber(1);
            signer.SetFieldName("sig");

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            new C2_02_SignHelloWorldWithTempFile().Sign(SRC, DEST, DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CMS, "Temp test", "Ghent");
        }
    }
}

c2_03_signemptyfield

Signing an empty text field with iText:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C2_03_SignEmptyField {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "field_signed1.pdf",
            "field_signed2.pdf",
            "field_signed3.pdf",
            "field_signed4.pdf"
    };

    public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        signer.getSignatureAppearance()
                .setReason(reason)
                .setLocation(location)

                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .setReuseAppearance(false);

        // This name corresponds to the name of the field that already exists in the document.
        signer.setFieldName(name);

        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        C2_03_SignEmptyField app = new C2_03_SignEmptyField();
        app.sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
                provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
        app.sign(SRC, "Signature1", DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA512,
                provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
        app.sign(SRC, "Signature1", DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256,
                provider.getName(), PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
        app.sign(SRC, "Signature1", DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.RIPEMD160,
                provider.getName(), PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_03_SignEmptyField
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "field_signed1.pdf",
            "field_signed2.pdf",
            "field_signed3.pdf",
            "field_signed4.pdf"
        };

        public void Sign(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            signer.GetSignatureAppearance()
                .SetReason(reason)
                .SetLocation(location)

                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .SetReuseAppearance(false);

            // This name corresponds to the name of the field that already exists in the document.
            signer.SetFieldName(name);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            C2_03_SignEmptyField app = new C2_03_SignEmptyField();
            app.Sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Test 1", "Ghent");
            app.Sign(SRC, "Signature1", DEST + RESULT_FILES[1], chain, pk,
                DigestAlgorithms.SHA512, PdfSigner.CryptoStandard.CMS,
                "Test 2", "Ghent");
            app.Sign(SRC, "Signature1", DEST + RESULT_FILES[2], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CADES,
                "Test 3", "Ghent");
            app.Sign(SRC, "Signature1", DEST + RESULT_FILES[3], chain, pk,
                DigestAlgorithms.RIPEMD160, PdfSigner.CryptoStandard.CADES,
                "Test 4", "Ghent");
        }
    }
}

c2_04_createemptyfield

Creating an empty text field with iText:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.PdfSignatureFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

public class C2_04_CreateEmptyField {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";

    public static final char[] PASSWORD = "password".toCharArray();
    public static final String SIGNAME = "Signature1";

    public static final String[] RESULT_FILES = new String[]{
            "hello_empty.pdf",
            "hello_empty2.pdf",
            "field_signed.pdf"
    };

    public void createPdf(String filename) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(filename));
        Document doc = new Document(pdfDoc);

        doc.add(new Paragraph("Hello World!"));

        // Create a signature form field
        PdfFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
                .setWidgetRectangle(new Rectangle(72, 632, 200, 100)).createSignature();
        field.getFirstFormAnnotation().setPage(1);

        // Set the widget properties
        field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT).setFlags(PdfAnnotation.PRINT);

        PdfDictionary mkDictionary = field.getWidgets().get(0).getAppearanceCharacteristics();
        if (null == mkDictionary) {
            mkDictionary = new PdfDictionary();
        }

        PdfArray black = new PdfArray();
        black.add(new PdfNumber(ColorConstants.BLACK.getColorValue()[0]));
        black.add(new PdfNumber(ColorConstants.BLACK.getColorValue()[1]));
        black.add(new PdfNumber(ColorConstants.BLACK.getColorValue()[2]));
        mkDictionary.put(PdfName.BC, black);

        field.getWidgets().get(0).setAppearanceCharacteristics(mkDictionary);

        PdfAcroForm.getAcroForm(pdfDoc, true).addField(field);

        Rectangle rect = new Rectangle(0, 0, 200, 100);
        PdfFormXObject xObject = new PdfFormXObject(rect);
        PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);
        canvas
                .setStrokeColor(ColorConstants.BLUE)
                .setFillColor(ColorConstants.LIGHT_GRAY)
                .rectangle(0 + 0.5, 0 + 0.5, 200 - 0.5, 100 - 0.5)
                .fillStroke()
                .setFillColor(ColorConstants.BLUE);
        new Canvas(canvas, rect).showTextAligned("SIGN HERE", 100, 50,
                TextAlignment.CENTER, (float) Math.toRadians(25));

        // Note that Acrobat doesn't show normal appearance in the highlight mode.
        field.getWidgets().get(0).setNormalAppearance(xObject.getPdfObject());

        doc.close();
    }

    public void addField(String src, String dest) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));

        // Create a signature form field
        PdfSignatureFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
                .setWidgetRectangle(new Rectangle(72, 632, 200, 100)).createSignature();

        field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_OUTLINE).setFlags(PdfAnnotation.PRINT);

        PdfAcroForm.getAcroForm(pdfDoc, true).addField(field);

        pdfDoc.close();
    }

    public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
                     String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        signer.getSignatureAppearance()
                .setReason(reason)
                .setLocation(location);

        signer.setFieldName(name);

        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        C2_04_CreateEmptyField app = new C2_04_CreateEmptyField();
        app.createPdf(DEST + RESULT_FILES[0]);
        app.addField(SRC, DEST + RESULT_FILES[1]);

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        app.sign(DEST + RESULT_FILES[0], SIGNAME, DEST + RESULT_FILES[2], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Test", "Ghent");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Colors;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_04_CreateEmptyField
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();
        public const String SIGNAME = "Signature1";

        public static readonly String[] RESULT_FILES =
        {
            "hello_empty.pdf",
            "hello_empty2.pdf",
            "field_signed.pdf"
        };

        public void CreatePdf(String filename)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(filename));
            Document doc = new Document(pdfDoc);

            doc.Add(new Paragraph("Hello World!"));

            // Create a signature form field
            PdfFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
                .SetWidgetRectangle(new Rectangle(72, 632, 200, 100)).CreateSignature();
            field.GetFirstFormAnnotation().SetPage(1);

            // Set the widget properties
            field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT).SetFlags(PdfAnnotation.PRINT);

            PdfDictionary mkDictionary = field.GetWidgets()[0].GetAppearanceCharacteristics();
            if (null == mkDictionary)
            {
                mkDictionary = new PdfDictionary();
            }

            PdfArray black = new PdfArray();
            black.Add(new PdfNumber(ColorConstants.BLACK.GetColorValue()[0]));
            black.Add(new PdfNumber(ColorConstants.BLACK.GetColorValue()[1]));
            black.Add(new PdfNumber(ColorConstants.BLACK.GetColorValue()[2]));
            mkDictionary.Put(PdfName.BC, black);

            field.GetWidgets()[0].SetAppearanceCharacteristics(mkDictionary);

            PdfFormCreator.GetAcroForm(pdfDoc, true).AddField(field);

            Rectangle rect = new Rectangle(0, 0, 200, 100);
            PdfFormXObject xObject = new PdfFormXObject(rect);
            PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);
            canvas
                .SetStrokeColor(ColorConstants.BLUE)
                .SetFillColor(ColorConstants.LIGHT_GRAY)
                .Rectangle(0 + 0.5, 0 + 0.5, 200 - 0.5, 100 - 0.5)
                .FillStroke()
                .SetFillColor(ColorConstants.BLUE);
            new Canvas(canvas, rect).ShowTextAligned("SIGN HERE", 100, 50,
                TextAlignment.CENTER, (float) (Math.PI / 180) * 25);

            // Note that Acrobat doesn't show normal appearance in the highlight mode.
            field.GetWidgets()[0].SetNormalAppearance(xObject.GetPdfObject());

            doc.Close();
        }

        public void AddField(String src, String dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));

            // Create a signature form field
            PdfSignatureFormField field = new SignatureFormFieldBuilder(pdfDoc, SIGNAME)
                .SetWidgetRectangle(new Rectangle(72, 632, 200, 100)).CreateSignature();

            field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_OUTLINE).SetFlags(PdfAnnotation.PRINT);

            PdfFormCreator.GetAcroForm(pdfDoc, true).AddField(field);

            pdfDoc.Close();
        }

        public void Sign(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            signer.GetSignatureAppearance()
                .SetReason(reason)
                .SetLocation(location);
            signer.SetFieldName(name);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            C2_04_CreateEmptyField appCreate = new C2_04_CreateEmptyField();
            appCreate.CreatePdf(DEST + RESULT_FILES[0]);
            appCreate.AddField(SRC, DEST + RESULT_FILES[1]);

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            new C2_04_CreateEmptyField().Sign(DEST + RESULT_FILES[0], SIGNAME, DEST + RESULT_FILES[2],
                chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Test", "Ghent");
        }
    }
}

c2_05_customappearance

Creating a custom appearance for the signature by adding a grey background:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C2_05_CustomAppearance {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "signature_custom.pdf"
    };

    public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider,
            PdfSigner.CryptoStandard subfilter,
            String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        PdfSignatureAppearance appearance = signer.getSignatureAppearance()
                .setReason(reason)
                .setLocation(location);

        // This name corresponds to the name of the field that already exists in the document.
        signer.setFieldName(name);

        // Get the background layer and draw a gray rectangle as a background.
        PdfFormXObject n0 = appearance.getLayer0();
        float x = n0.getBBox().toRectangle().getLeft();
        float y = n0.getBBox().toRectangle().getBottom();
        float width = n0.getBBox().toRectangle().getWidth();
        float height = n0.getBBox().toRectangle().getHeight();
        PdfCanvas canvas = new PdfCanvas(n0, signer.getDocument());
        canvas.setFillColor(ColorConstants.LIGHT_GRAY);
        canvas.rectangle(x, y, width, height);
        canvas.fill();

        // Set the signature information on layer 2
        PdfFormXObject n2 = appearance.getLayer2();
        Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
        new Canvas(n2, signer.getDocument()).add(p);

        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        new C2_05_CustomAppearance().sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Custom appearance example", "Ghent");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using iText.Kernel.Colors;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_05_CustomAppearance
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "signature_custom.pdf"
        };

        public void Sign(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance
                .SetReason(reason)
                .SetLocation(location);

            // This name corresponds to the name of the field that already exists in the document.
            signer.SetFieldName(name);

            // Get the background layer and draw a gray rectangle as a background.
            PdfFormXObject n0 = appearance.GetLayer0();
            float x = n0.GetBBox().ToRectangle().GetLeft();
            float y = n0.GetBBox().ToRectangle().GetBottom();
            float width = n0.GetBBox().ToRectangle().GetWidth();
            float height = n0.GetBBox().ToRectangle().GetHeight();
            PdfCanvas canvas = new PdfCanvas(n0, signer.GetDocument());
            canvas.SetFillColor(ColorConstants.LIGHT_GRAY);
            canvas.Rectangle(x, y, width, height);
            canvas.Fill();

            // Set the signature information on layer 2
            PdfFormXObject n2 = appearance.GetLayer2();
            Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
            new Canvas(n2, signer.GetDocument()).Add(p);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            new C2_05_CustomAppearance().Sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Custom appearance example", "Ghent");
        }
    }
}

c2_06_signatureappearance

Creating custom text, custom fonts and using right-to-left writing in a signature:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.font.PdfFontFactory.EmbeddingStrategy;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.properties.BaseDirection;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

public class C2_06_SignatureAppearance {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
    public static final String IMG = "./src/test/resources/img/1t3xt.gif";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "signature_appearance1.pdf",
            "signature_appearance2.pdf",
            "signature_appearance3.pdf",
            "signature_appearance4.pdf"
    };

    public void sign1(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);

        // This name corresponds to the name of the field that already exists in the document.
        signer.setFieldName(name);

        // Set the custom text and a custom font
        appearance.setLayer2Text("This document was signed by Bruno Specimen");
        appearance.setLayer2Font(PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN));

        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public void sign2(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        signer.setFieldName(name);

        // Creating the appearance for layer 2
        PdfFormXObject n2 = appearance.getLayer2();

        // Set custom text, custom font, and right-to-left writing.
        // Characters: لورانس العرب
        Text text = new Text("\u0644\u0648\u0631\u0627\u0646\u0633 \u0627\u0644\u0639\u0631\u0628");
        text.setFont(PdfFontFactory.createFont("./src/test/resources/font/NotoNaskhArabic-Regular.ttf",
                PdfEncodings.IDENTITY_H, EmbeddingStrategy.PREFER_EMBEDDED));
        text.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);
        new Canvas(n2, signer.getDocument()).add(new Paragraph(text).setTextAlignment(TextAlignment.RIGHT));

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public void sign3(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        signer.setFieldName(name);

        // Set a custom text and a background image
        appearance.setLayer2Text("This document was signed by Bruno Specimen");
        appearance.setImage(ImageDataFactory.create(IMG));
        appearance.setImageScale(1);

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public void sign4(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        signer.setFieldName(name);

        // Set a custom text and a scaled background image
        appearance.setLayer2Text("This document was signed by Bruno Specimen");
        appearance.setImage(ImageDataFactory.create(IMG));
        appearance.setImageScale(-1);

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        C2_06_SignatureAppearance app = new C2_06_SignatureAppearance();
        String signatureName = "Signature1";
        String signatureReason = "Custom appearance example";
        String location = "Ghent";
        app.sign1(SRC, signatureName, DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                signatureReason, location);

        app.sign2(SRC, signatureName, DEST + RESULT_FILES[1], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                signatureReason, location);

        app.sign3(SRC, signatureName, DEST + RESULT_FILES[2], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                signatureReason, location);

        app.sign4(SRC, signatureName, DEST + RESULT_FILES[3], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                signatureReason, location);
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using iText.IO.Font;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.IO.Font.Constants;
using iText.IO.Image;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_06_SignatureAppearance
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string IMG = "../../../resources/img/1t3xt.gif";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "signature_appearance1.pdf",
            "signature_appearance2.pdf",
            "signature_appearance3.pdf",
            "signature_appearance4.pdf"
        };

        public void Sign1(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance
                .SetReason(reason)
                .SetLocation(location);

            // This name corresponds to the name of the field that already exists in the document.
            signer.SetFieldName(name);

            // Set the custom text and a custom font
            appearance.SetLayer2Text("This document was signed by Bruno Specimen");
            appearance.SetLayer2Font(PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN));

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public void Sign2(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);
            signer.SetFieldName(name);

            // Creating the appearance for layer 2
            PdfFormXObject n2 = appearance.GetLayer2();

            // Custom text, custom font, and right-to-left writing
            // Characters: لورانس العرب
            Text text = new Text("\u0644\u0648\u0631\u0627\u0646\u0633 \u0627\u0644\u0639\u0631\u0628");
            text.SetFont(PdfFontFactory.CreateFont("../../../resources/font/NotoNaskhArabic-Regular.ttf",
                PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED));
            text.SetBaseDirection(BaseDirection.RIGHT_TO_LEFT);
            new Canvas(n2, signer.GetDocument()).Add(new Paragraph(text).SetTextAlignment(TextAlignment.RIGHT));

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public void Sign3(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);
            signer.SetFieldName(name);

            // Set a custom text and background image
            appearance.SetLayer2Text("This document was signed by Bruno Specimen");
            appearance.SetImage(ImageDataFactory.Create(IMG));
            appearance.SetImageScale(1);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public void Sign4(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);
            signer.SetFieldName(name);

            // Set a custom text and a scaled background image
            appearance.SetLayer2Text("This document was signed by Bruno Specimen");
            appearance.SetImage(ImageDataFactory.Create(IMG));
            appearance.SetImageScale(-1);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            C2_06_SignatureAppearance app = new C2_06_SignatureAppearance();
            app.Sign1(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Custom appearance example", "Ghent");

            app.Sign2(SRC, "Signature1", DEST + RESULT_FILES[1], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Custom appearance example", "Ghent");

            app.Sign3(SRC, "Signature1", DEST + RESULT_FILES[2], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Custom appearance example", "Ghent");

            app.Sign4(SRC, "Signature1", DEST + RESULT_FILES[3], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Custom appearance example", "Ghent");
        }
    }
}


c2_07_signatureappearances

Adding a custom image:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Date;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C2_07_SignatureAppearances {
    public static final String DEST = "./target/signatures/chapter02/";

    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";
    public static final String IMG = "./src/test/resources/img/1t3xt.gif";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "signature_appearance_1.pdf",
            "signature_appearance_2.pdf",
            "signature_appearance_3.pdf",
            "signature_appearance_4.pdf"
    };

    public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location,
            PdfSignatureAppearance.RenderingMode renderingMode, ImageData image)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);

        // This name corresponds to the name of the field that already exists in the document.
        signer.setFieldName(name);

        appearance.setLayer2Text("Signed on " + new Date().toString());

        // Set the rendering mode for this signature.
        appearance.setRenderingMode(renderingMode);

        // Set the Image object to render when the rendering mode is set to RenderingMode.GRAPHIC
        // or RenderingMode.GRAPHIC_AND_DESCRIPTION.
        appearance.setSignatureGraphic(image);

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);
        ImageData image = ImageDataFactory.create(IMG);

        C2_07_SignatureAppearances app = new C2_07_SignatureAppearances();
        String signatureName = "Signature1";
        String location = "Ghent";
        app.sign(SRC, signatureName, DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Appearance 1", location, PdfSignatureAppearance.RenderingMode.DESCRIPTION, null);

        app.sign(SRC, signatureName, DEST + RESULT_FILES[1], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Appearance 2", location, PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION, null);

        app.sign(SRC, signatureName, DEST + RESULT_FILES[2], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Appearance 3", location, PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION, image);

        app.sign(SRC, signatureName, DEST + RESULT_FILES[3], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS,
                "Appearance 4", location, PdfSignatureAppearance.RenderingMode.GRAPHIC, image);
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.IO.Image;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_07_SignatureAppearances
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";
        public static readonly string IMG = "../../../resources/img/1t3xt.gif";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "signature_appearance_1.pdf",
            "signature_appearance_2.pdf",
            "signature_appearance_3.pdf",
            "signature_appearance_4.pdf"
        };

        public void Sign(String src, String name, String dest, X509Certificate[] chain,
            ICipherParameters pk, String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            String reason, String location, PdfSignatureAppearance.RenderingMode renderingMode, ImageData image)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);

            // This name corresponds to the name of the field that already exists in the document.
            signer.SetFieldName(name);

            appearance.SetLayer2Text("Signed on " + DateTime.Now);

            // Set the rendering mode for this signature.
            appearance.SetRenderingMode(renderingMode);

            // Set the Image object to render when the rendering mode is set to RenderingMode.GRAPHIC
            // or RenderingMode.GRAPHIC_AND_DESCRIPTION.
            appearance.SetSignatureGraphic(image);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            ImageData image = ImageDataFactory.Create(IMG);

            C2_07_SignatureAppearances app = new C2_07_SignatureAppearances();
            String signatureName = "Signature1";
            String location = "Ghent";
            app.Sign(SRC, signatureName, DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Appearance 1", location, PdfSignatureAppearance.RenderingMode.DESCRIPTION, null);

            app.Sign(SRC, signatureName, DEST + RESULT_FILES[1], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Appearance 2", location, PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION, null);

            app.Sign(SRC, signatureName, DEST + RESULT_FILES[2], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Appearance 3", location, PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION, image);

            app.Sign(SRC, signatureName, DEST + RESULT_FILES[3], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Appearance 4", location, PdfSignatureAppearance.RenderingMode.GRAPHIC, image);
        }
    }
}

c2_08_signaturemetadata

Adding metadata to the signature dictionary:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C2_08_SignatureMetadata {
    public static final String DEST = "./target/signatures/chapter02/";
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello_to_sign.pdf";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "field_metadata.pdf"
    };

    public void sign(String src, String name, String dest, Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
            String reason, String location, String contact, final String fullName)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        appearance.setContact(contact);

        // This name corresponds to the name of the field that already exists in the document.
        signer.setFieldName(name);

        // Set the signature event to allow modification of the signature dictionary.
        signer.setSignatureEvent(
                new PdfSigner.ISignatureEvent() {
                    @Override
                    public void getSignatureDictionary(PdfSignature sig) {
                        sig.put(PdfName.Name, new PdfString(fullName));
                    }
                }
        );

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        C2_08_SignatureMetadata app = new C2_08_SignatureMetadata();
        app.sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
                provider.getName(), PdfSigner.CryptoStandard.CMS, "Test metadata",
                "Ghent", "555 123 456", "Bruno L. Specimen");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_08_SignatureMetadata
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello_to_sign.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "field_metadata.pdf"
        };

        public void Sign(String src, String name, String dest, X509Certificate[] chain, ICipherParameters pk,
            String digestAlgorithm, PdfSigner.CryptoStandard subfilter, String reason, String location,
            String contact, String fullName)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);
            appearance.SetContact(contact);

            signer.SetFieldName(name);

            // Set the signature event to allow modification of the signature dictionary.
            signer.SetSignatureEvent(new CustomISignatureEvent(fullName));

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            C2_08_SignatureMetadata app = new C2_08_SignatureMetadata();
            app.Sign(SRC, "Signature1", DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Test metadata", "Ghent", "555 123 456", "Bruno L. Specimen");
        }

        private class CustomISignatureEvent : PdfSigner.ISignatureEvent
        {
            private readonly String fullName;

            public CustomISignatureEvent(String fullName)
            {
                this.fullName = fullName;
            }

            public void GetSignatureDictionary(PdfSignature sig)
            {
                sig.Put(PdfName.Name, new PdfString(fullName));
            }
        }
    }
}

c2_09_signaturetypes

Ordinary (approval) and Certification (author) signatures:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextAnnotation;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C2_09_SignatureTypes {
    public static final String DEST = "./target/signatures/chapter02/";
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "hello_level_1.pdf", "hello_level_2.pdf",
            "hello_level_3.pdf", "hello_level_4.pdf",
            "hello_level_1_annotated.pdf", "hello_level_2_annotated.pdf",
            "hello_level_3_annotated.pdf", "hello_level_4_annotated.pdf",
            "hello_level_1_annotated_wrong.pdf", "hello_level_1_text.pdf",
            "hello_level_1_double.pdf", "hello_level_2_double.pdf",
            "hello_level_3_double.pdf", "hello_level_4_double.pdf",
    };

    public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, int certificationLevel,
            String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

        // Create the signature appearance
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);

        Rectangle rect = new Rectangle(36, 648, 200, 100);
        appearance.setPageRect(rect);
        appearance.setPageNumber(1);
        signer.setFieldName("sig");

        /* Set the document's certification level. This parameter defines if changes are allowed
         * after the applying of the signature.
         */
        signer.setCertificationLevel(certificationLevel);

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
    }

    public void addText(String src, String dest) throws IOException {
        PdfReader reader = new PdfReader(src);
        PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest), new StampingProperties().useAppendMode());
        PdfPage firstPage = pdfDoc.getFirstPage();

        new Canvas(firstPage, firstPage.getPageSize()).showTextAligned("TOP SECRET", 36, 820,
                TextAlignment.LEFT);

        pdfDoc.close();
    }

    public void addAnnotation(String src, String dest) throws IOException {
        PdfReader reader = new PdfReader(src);
        PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest), new StampingProperties().useAppendMode());

        PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
                .setOpen(true)
                .setIconName(new PdfName("Comment"))
                .setTitle(new PdfString("Finally Signed!"))
                .setContents("Bruno Specimen has finally signed the document");
        pdfDoc.getFirstPage().addAnnotation(comment);

        pdfDoc.close();
    }

    public void addWrongAnnotation(String src, String dest) throws IOException {
        PdfReader reader = new PdfReader(src);
        PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest));

        PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
                .setOpen(true)
                .setIconName(new PdfName("Comment"))
                .setTitle(new PdfString("Finally Signed!"))
                .setContents("Bruno Specimen has finally signed the document");
        pdfDoc.getFirstPage().addAnnotation(comment);

        pdfDoc.close();
    }

    public void signAgain(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
            String provider, PdfSigner.CryptoStandard subfilter, String reason, String location)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());

        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        appearance.setReuseAppearance(false);
        Rectangle rect = new Rectangle(36, 700, 200, 100);
        appearance.setPageRect(rect);
        appearance.setPageNumber(1);
        signer.setFieldName("Signature2");

        PrivateKeySignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);

    }

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        C2_09_SignatureTypes app = new C2_09_SignatureTypes();
        app.sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, PdfSigner.NOT_CERTIFIED,
                "Test 1", "Ghent");
        app.sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS,
                "Test 1", "Ghent");
        app.sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING,
                "Test 1", "Ghent");
        app.sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED,
                "Test 1", "Ghent");

        app.addAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[4]);
        app.addAnnotation(DEST + RESULT_FILES[1], DEST + RESULT_FILES[5]);
        app.addAnnotation(DEST + RESULT_FILES[2], DEST + RESULT_FILES[6]);
        app.addAnnotation(DEST + RESULT_FILES[3], DEST + RESULT_FILES[7]);

        app.addWrongAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[8]);
        app.addText(DEST + RESULT_FILES[0], DEST + RESULT_FILES[9]);

        app.signAgain(DEST + RESULT_FILES[0], DEST + RESULT_FILES[10], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
        app.signAgain(DEST + RESULT_FILES[1], DEST + RESULT_FILES[11], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
        app.signAgain(DEST + RESULT_FILES[2], DEST + RESULT_FILES[12], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
        app.signAgain(DEST + RESULT_FILES[3], DEST + RESULT_FILES[13], chain, pk,
                DigestAlgorithms.SHA256, provider.getName(),
                PdfSigner.CryptoStandard.CMS, "Second signature test", "Gent");
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Properties;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_09_SignatureTypes
    {
        public static readonly string DEST = "results/signatures/chapter02/";

        public static readonly string KEYSTORE = "../../../resources/encryption/ks";
        public static readonly string SRC = "../../../resources/pdfs/hello.pdf";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "hello_level_1.pdf", "hello_level_2.pdf",
            "hello_level_3.pdf", "hello_level_4.pdf",
            "hello_level_1_annotated.pdf", "hello_level_2_annotated.pdf",
            "hello_level_3_annotated.pdf", "hello_level_4_annotated.pdf",
            "hello_level_1_annotated_wrong.pdf", "hello_level_1_text.pdf",
            "hello_level_1_double.pdf", "hello_level_2_double.pdf",
            "hello_level_3_double.pdf", "hello_level_4_double.pdf",
        };

        public void Sign(String src, String dest, X509Certificate[] chain, ICipherParameters pk,
            String digestAlgorithm, PdfSigner.CryptoStandard subfilter,
            int certificationLevel, String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());

            // Create the signature appearance
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);

            Rectangle rect = new Rectangle(36, 648, 200, 100);
            appearance.SetPageRect(rect).SetPageNumber(1);
            signer.SetFieldName("sig");

            /* Set the document's certification level. This parameter defines if changes are allowed
             * after the applying of the signature.
             */
            signer.SetCertificationLevel(certificationLevel);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public void AddText(String src, String dest)
        {
            PdfReader reader = new PdfReader(src);
            PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest),
                new StampingProperties().UseAppendMode());
            PdfPage firstPage = pdfDoc.GetFirstPage();

            new Canvas(firstPage, firstPage.GetPageSize()).ShowTextAligned("TOP SECRET",
                36, 820, TextAlignment.LEFT);

            pdfDoc.Close();
        }

        public void AddAnnotation(String src, String dest)
        {
            PdfReader reader = new PdfReader(src);
            PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest),
                new StampingProperties().UseAppendMode());

            PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
                .SetOpen(true)
                .SetIconName(new PdfName("Comment"))
                .SetTitle(new PdfString("Finally Signed!"))
                .SetContents("Bruno Specimen has finally signed the document");
            pdfDoc.GetFirstPage().AddAnnotation(comment);

            pdfDoc.Close();
        }

        public void AddWrongAnnotation(String src, String dest)
        {
            PdfReader reader = new PdfReader(src);
            PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(dest));

            PdfAnnotation comment = new PdfTextAnnotation(new Rectangle(200, 800, 50, 20))
                .SetOpen(true)
                .SetIconName(new PdfName("Comment"))
                .SetTitle(new PdfString("Finally Signed!"))
                .SetContents("Bruno Specimen has finally signed the document");
            pdfDoc.GetFirstPage().AddAnnotation(comment);

            pdfDoc.Close();
        }

        public void SignAgain(String src, String dest, X509Certificate[] chain, ICipherParameters pk,
            String digestAlgorithm, PdfSigner.CryptoStandard subfilter, String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());

            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance.SetReason(reason);
            appearance.SetLocation(location);
            appearance.SetReuseAppearance(false);
            Rectangle rect = new Rectangle(36, 700, 200, 100);
            appearance.SetPageRect(rect).SetPageNumber(1);
            signer.SetFieldName("Signature2");

            IX509Certificate[] certificateWrappers = new IX509Certificate[chain.Length];
            for (int i = 0; i < certificateWrappers.Length; ++i) {
                certificateWrappers[i] = new X509CertificateBC(chain[i]);
            }
            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), digestAlgorithm);
            signer.SignDetached(pks, certificateWrappers, null, null, null, 0, subfilter);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }

            C2_09_SignatureTypes app = new C2_09_SignatureTypes();
            app.Sign(SRC, DEST + RESULT_FILES[0], chain, pk, DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CMS, PdfSigner.NOT_CERTIFIED,
                "Test 1", "Ghent");
            app.Sign(SRC, DEST + RESULT_FILES[1], chain, pk, DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS,
                "Test 1", "Ghent");
            app.Sign(SRC, DEST + RESULT_FILES[2], chain, pk, DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_FORM_FILLING,
                "Test 1", "Ghent");
            app.Sign(SRC, DEST + RESULT_FILES[3], chain, pk, DigestAlgorithms.SHA256,
                PdfSigner.CryptoStandard.CMS, PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED,
                "Test 1", "Ghent");

            app.AddAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[4]);
            app.AddAnnotation(DEST + RESULT_FILES[1], DEST + RESULT_FILES[5]);
            app.AddAnnotation(DEST + RESULT_FILES[2], DEST + RESULT_FILES[6]);
            app.AddAnnotation(DEST + RESULT_FILES[3], DEST + RESULT_FILES[7]);

            app.AddWrongAnnotation(DEST + RESULT_FILES[0], DEST + RESULT_FILES[8]);
            app.AddText(DEST + RESULT_FILES[0], DEST + RESULT_FILES[9]);

            app.SignAgain(DEST + RESULT_FILES[0], DEST + RESULT_FILES[10], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Second signature test", "Gent");
            app.SignAgain(DEST + RESULT_FILES[1], DEST + RESULT_FILES[11], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Second signature test", "Gent");
            app.SignAgain(DEST + RESULT_FILES[2], DEST + RESULT_FILES[12], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Second signature test", "Gent");
            app.SignAgain(DEST + RESULT_FILES[3], DEST + RESULT_FILES[13], chain, pk,
                DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS,
                "Second signature test", "Gent");
        }
    }
}


c2_10_sequentialsignatures

Sequential signatures in PDFs:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

public class C2_10_SequentialSignatures {

    public static final String DEST = "./target/signatures/chapter02/";
    public static final String FORM = "./target/signatures/chapter02/multiple_signatures.pdf";

    public static final String ALICE = "./src/test/resources/encryption/alice";
    public static final String BOB = "./src/test/resources/encryption/bob";
    public static final String CAROL = "./src/test/resources/encryption/carol";
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "signed_by_alice.pdf", "signed_by_bob.pdf",
            "signed_by_carol.pdf", "signed_by_alice2.pdf",
            "signed_by_bob2.pdf", "signed_by_carol2.pdf",
            "signed_by_alice3.pdf", "signed_by_bob3.pdf",
            "signed_by_carol3.pdf", "signed_by_alice4.pdf",
            "signed_by_bob4.pdf", "signed_by_carol4.pdf",
    };

    public void createForm() throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
        Document doc = new Document(pdfDoc);

        Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
        table.addCell("Signer 1: Alice");
        table.addCell(createSignatureFieldCell("sig1"));
        table.addCell("Signer 2: Bob");
        table.addCell(createSignatureFieldCell("sig2"));
        table.addCell("Signer 3: Carol");
        table.addCell(createSignatureFieldCell("sig3"));
        doc.add(table);

        doc.close();
    }

    protected Cell createSignatureFieldCell(String name) {
        Cell cell = new Cell();
        cell.setHeight(50);
        cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name));
        return cell;
    }

    public void sign(String keystore, String provider, int level, String src, String name, String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());

        // Set the signer options
        signer.setFieldName(name);
        signer.setCertificationLevel(level);

        IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);

        C2_10_SequentialSignatures app = new C2_10_SequentialSignatures();
        app.createForm();

        /* Alice signs certification signature (allowing form filling),
         * then Bob and Carol sign approval signature (not certified).
         */
        app.sign(ALICE, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, FORM, "sig1", DEST + RESULT_FILES[0]);
        app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[0], "sig2",
                DEST + RESULT_FILES[1]);
        app.sign(CAROL, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[1], "sig3",
                DEST + RESULT_FILES[2]);

        /* Alice signs approval signatures (not certified), so does Bob
         * and then Carol signs certification signature allowing form filling.
         */
        app.sign(ALICE, provider.getName(), PdfSigner.NOT_CERTIFIED, FORM, "sig1", DEST + RESULT_FILES[3]);
        app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[3], "sig2",
                DEST + RESULT_FILES[4]);
        app.sign(CAROL, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[4], "sig3",
                DEST + RESULT_FILES[5]);

        /* Alice signs approval signatures (not certified), so does Bob
         * and then Carol signs certification signature forbidding any changes to the document.
         */
        app.sign(ALICE, provider.getName(), PdfSigner.NOT_CERTIFIED, FORM, "sig1", DEST + RESULT_FILES[6]);
        app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[6], "sig2",
                DEST + RESULT_FILES[7]);
        app.sign(CAROL, provider.getName(), PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED, DEST + RESULT_FILES[7], "sig3",
                DEST + RESULT_FILES[8]);

        /* Alice signs certification signature (allowing form filling), then Bob signs approval
         * signatures (not certified) and then Carol signs certification signature allowing form filling.
         */
        app.sign(ALICE, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, FORM, "sig1", DEST + RESULT_FILES[9]);
        app.sign(BOB, provider.getName(), PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[9], "sig2",
                DEST + RESULT_FILES[10]);
        app.sign(CAROL, provider.getName(), PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[10], "sig3",
                DEST + RESULT_FILES[11]);
    }

    private static class SignatureFieldCellRenderer extends CellRenderer {
        public String name;

        public SignatureFieldCellRenderer(Cell modelElement, String name) {
            super(modelElement);
            this.name = name;
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfFormField field = new SignatureFormFieldBuilder(drawContext.getDocument(), name)
                    .setWidgetRectangle(getOccupiedAreaBBox()).createSignature();
            field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
            field.getWidgets().get(0).setFlags(PdfAnnotation.PRINT);
            PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
        }
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_10_SequentialSignatures
    {
        public static readonly string DEST = "results/signatures/chapter02/";
        public static readonly string FORM = "results/signatures/chapter02/multiple_signatures.pdf";

        public static readonly string ALICE = "../../../resources/encryption/alice";
        public static readonly string BOB = "../../../resources/encryption/bob";
        public static readonly string CAROL = "../../../resources/encryption/carol";
        public static readonly string KEYSTORE = "../../../resources/encryption/ks";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "signed_by_alice.pdf", "signed_by_bob.pdf",
            "signed_by_carol.pdf", "signed_by_alice2.pdf",
            "signed_by_bob2.pdf", "signed_by_carol2.pdf",
            "signed_by_alice3.pdf", "signed_by_bob3.pdf",
            "signed_by_carol3.pdf", "signed_by_alice4.pdf",
            "signed_by_bob4.pdf", "signed_by_carol4.pdf",
        };

        public void CreateForm()
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
            Document doc = new Document(pdfDoc);

            Table table = new Table(1).UseAllAvailableWidth();
            table.AddCell("Signer 1: Alice");
            table.AddCell(CreateSignatureFieldCell("sig1"));
            table.AddCell("Signer 2: Bob");
            table.AddCell(CreateSignatureFieldCell("sig2"));
            table.AddCell("Signer 3: Carol");
            table.AddCell(CreateSignatureFieldCell("sig3"));
            doc.Add(table);

            doc.Close();
        }

        protected Cell CreateSignatureFieldCell(String name)
        {
            Cell cell = new Cell();
            cell.SetHeight(50);
            cell.SetNextRenderer(new SignatureFieldCellRenderer(cell, name));
            return cell;
        }

        public void Sign(String keystore, int level, String src, String name, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());

            // Set the signer options
            signer.SetFieldName(name);
            signer.SetCertificationLevel(level);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);

            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, chain, null, null, null, 0,
                PdfSigner.CryptoStandard.CMS);
        }

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            C2_10_SequentialSignatures app = new C2_10_SequentialSignatures();
            app.CreateForm();

            /* Alice signs certification signature (allowing form filling),
             * then Bob and Carol sign approval signature (not certified).
             */
            app.Sign(ALICE, PdfSigner.CERTIFIED_FORM_FILLING, FORM,
                "sig1", DEST + RESULT_FILES[0]);
            app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[0],
                "sig2", DEST + RESULT_FILES[1]);
            app.Sign(CAROL, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[1],
                "sig3", DEST + RESULT_FILES[2]);

            /* Alice signs approval signatures (not certified), so does Bob
             * and then Carol signs certification signature allowing form filling.
             */
            app.Sign(ALICE, PdfSigner.NOT_CERTIFIED, FORM,
                "sig1", DEST + RESULT_FILES[3]);
            app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[3],
                "sig2", DEST + RESULT_FILES[4]);
            app.Sign(CAROL, PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[4],
                "sig3", DEST + RESULT_FILES[5]);

            /* Alice signs approval signatures (not certified), so does Bob
             * and then Carol signs certification signature forbidding any changes to the document.
             */
            app.Sign(ALICE, PdfSigner.NOT_CERTIFIED, FORM,
                "sig1", DEST + RESULT_FILES[6]);
            app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[6],
                "sig2", DEST + RESULT_FILES[7]);
            app.Sign(CAROL, PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED, DEST + RESULT_FILES[7],
                "sig3", DEST + RESULT_FILES[8]);

            /* Alice signs certification signature (allowing form filling), then Bob signs approval
             * signatures (not certified) and then Carol signs certification signature allowing form filling.
             */
            app.Sign(ALICE, PdfSigner.CERTIFIED_FORM_FILLING, FORM,
                "sig1", DEST + RESULT_FILES[9]);
            app.Sign(BOB, PdfSigner.NOT_CERTIFIED, DEST + RESULT_FILES[9],
                "sig2", DEST + RESULT_FILES[10]);
            app.Sign(CAROL, PdfSigner.CERTIFIED_FORM_FILLING, DEST + RESULT_FILES[10],
                "sig3", DEST + RESULT_FILES[11]);
        }

        private class SignatureFieldCellRenderer : CellRenderer
        {
            public String name;

            public SignatureFieldCellRenderer(Cell modelElement, String name)
                : base(modelElement)
            {
                this.name = name;
            }

            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfFormField field = new SignatureFormFieldBuilder(drawContext.GetDocument(), name)
                    .SetWidgetRectangle(GetOccupiedAreaBBox()).CreateSignature();
                field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
                field.GetWidgets()[0].SetFlags(PdfAnnotation.PRINT);
                PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
            }
        }
    }
}

c2_11_signatureworkflow

An example where multiple signatures are required:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.forms.fields.TextFormFieldBuilder;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

public class C2_11_SignatureWorkflow {
    public static final String DEST = "./target/signatures/chapter02/";
    public static final String FORM = "./target/signatures/chapter02/form.pdf";

    public static final String ALICE = "./src/test/resources/encryption/alice";
    public static final String BOB = "./src/test/resources/encryption/bob";
    public static final String CAROL = "./src/test/resources/encryption/carol";
    public static final String DAVE = "./src/test/resources/encryption/dave";
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "step1_signed_by_alice.pdf", "step2_signed_by_alice_and_filled_out_by_bob.pdf",
            "step3_signed_by_alice_and_bob.pdf", "step4_signed_by_alice_and_bob_filled_out_by_carol.pdf",
            "step5_signed_by_alice_bob_and_carol.pdf", "step6_signed_by_alice_bob_carol_and_dave.pdf"
    };

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);

        C2_11_SignatureWorkflow app = new C2_11_SignatureWorkflow();
        app.createForm();

        String aliceCertifiedFile = DEST + RESULT_FILES[0];
        app.certify(ALICE, provider.getName(), FORM, "sig1", aliceCertifiedFile);

        String bobFilledFile = DEST + RESULT_FILES[1];
        String bobSignedFile = DEST + RESULT_FILES[2];
        app.fillOut(aliceCertifiedFile, bobFilledFile,
                "approved_bob", "Read and Approved by Bob");
        app.sign(BOB, provider.getName(), bobFilledFile, "sig2",
                bobSignedFile);

        String carolFilledFile = DEST + RESULT_FILES[3];
        String carolSignedFile = DEST + RESULT_FILES[4];
        app.fillOut(bobSignedFile, carolFilledFile,
                "approved_carol", "Read and Approved by Carol");
        app.sign(CAROL, provider.getName(), carolFilledFile, "sig3",
                carolSignedFile);

        String daveFilledCertifiedFile = DEST + RESULT_FILES[5];
        app.fillOutAndSign(DAVE, provider.getName(), carolSignedFile, "sig4",
                "approved_dave", "Read and Approved by Dave", daveFilledCertifiedFile);
    }

    public void createForm() throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
        Document doc = new Document(pdfDoc);

        Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
        table.addCell("Written by Alice");
        table.addCell(createSignatureFieldCell("sig1"));
        table.addCell("For approval by Bob");
        table.addCell(createTextFieldCell("approved_bob"));
        table.addCell(createSignatureFieldCell("sig2"));
        table.addCell("For approval by Carol");
        table.addCell(createTextFieldCell("approved_carol"));
        table.addCell(createSignatureFieldCell("sig3"));
        table.addCell("For approval by Dave");
        table.addCell(createTextFieldCell("approved_dave"));
        table.addCell(createSignatureFieldCell("sig4"));
        doc.add(table);

        doc.close();
    }

    public void certify(String keystore, String provider, String src, String name, String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());

        // Set signer options
        signer.setFieldName(name);
        signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);

        IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
    }

    public void fillOut(String src, String dest, String name, String value) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
                new StampingProperties().useAppendMode());

        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
        form.getField(name).setValue(value);
        form.getField(name).setReadOnly(true);

        pdfDoc.close();
    }

    public void sign(String keystore, String provider, String src, String name, String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
        signer.setFieldName(name);

        IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
    }

    public void fillOutAndSign(String keystore, String provider, String src, String name, String fname, String value,
            String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
        signer.setFieldName(name);

        PdfAcroForm form = PdfAcroForm.getAcroForm(signer.getDocument(), true);
        form.getField(fname).setValue(value);
        form.getField(fname).setReadOnly(true);

        IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
    }

    protected static Cell createTextFieldCell(String name) {
        Cell cell = new Cell();
        cell.setHeight(20);
        cell.setNextRenderer(new TextFieldCellRenderer(cell, name));
        return cell;
    }

    protected static Cell createSignatureFieldCell(String name) {
        Cell cell = new Cell();
        cell.setHeight(50);
        cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name));
        return cell;
    }


    private static class TextFieldCellRenderer extends CellRenderer {
        public String name;

        public TextFieldCellRenderer(Cell modelElement, String name) {
            super(modelElement);
            this.name = name;
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfFormField field = new TextFormFieldBuilder(drawContext.getDocument(), name)
                    .setWidgetRectangle(getOccupiedAreaBBox()).createText();
            PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
        }
    }


    private static class SignatureFieldCellRenderer extends CellRenderer {
        public String name;

        public SignatureFieldCellRenderer(Cell modelElement, String name) {
            super(modelElement);
            this.name = name;
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfFormField field = new SignatureFormFieldBuilder(drawContext.getDocument(), name)
                    .setWidgetRectangle(getOccupiedAreaBBox()).createSignature();
            field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
            field.getWidgets().get(0).setFlags(PdfAnnotation.PRINT);
            PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
        }
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_11_SignatureWorkflow
    {
        public static readonly string DEST = "results/signatures/chapter02/";
        public static readonly string FORM = "results/signatures/chapter02/form.pdf";

        public static readonly string ALICE = "../../../resources/encryption/alice";
        public static readonly string BOB = "../../../resources/encryption/bob";
        public static readonly string CAROL = "../../../resources/encryption/carol";
        public static readonly string DAVE = "../../../resources/encryption/dave";
        public static readonly string KEYSTORE = "../../../resources/encryption/ks";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "step1_signed_by_alice.pdf", "step2_signed_by_alice_and_filled_out_by_bob.pdf",
            "step3_signed_by_alice_and_bob.pdf", "step4_signed_by_alice_and_bob_filled_out_by_carol.pdf",
            "step5_signed_by_alice_bob_and_carol.pdf", "step6_signed_by_alice_bob_carol_and_dave.pdf"
        };

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            C2_11_SignatureWorkflow app = new C2_11_SignatureWorkflow();
            app.CreateForm();

            String aliceCertifiedFile = DEST + RESULT_FILES[0];
            app.Certify(ALICE, FORM, "sig1", aliceCertifiedFile);

            String bobFilledFile = DEST + RESULT_FILES[1];
            String bobSignedFile = DEST + RESULT_FILES[2];
            app.FillOut(aliceCertifiedFile, bobFilledFile, "approved_bob", "Read and Approved by Bob");
            app.Sign(BOB, bobFilledFile, "sig2", bobSignedFile);

            String carolFilledFile = DEST + RESULT_FILES[3];
            String carolSignedFile = DEST + RESULT_FILES[4];
            app.FillOut(bobSignedFile, carolFilledFile, "approved_carol", "Read and Approved by Carol");
            app.Sign(CAROL, carolFilledFile, "sig3", carolSignedFile);

            String daveFilledCertifiedFile = DEST + RESULT_FILES[5];
            app.FillOutAndSign(DAVE, carolSignedFile, "sig4", "approved_dave",
                "Read and Approved by Dave", daveFilledCertifiedFile);
        }

        public void CreateForm()
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
            Document doc = new Document(pdfDoc);

            Table table = new Table(1).UseAllAvailableWidth();
            table.AddCell("Written by Alice");
            table.AddCell(CreateSignatureFieldCell("sig1"));
            table.AddCell("For approval by Bob");
            table.AddCell(CreateTextFieldCell("approved_bob"));
            table.AddCell(CreateSignatureFieldCell("sig2"));
            table.AddCell("For approval by Carol");
            table.AddCell(CreateTextFieldCell("approved_carol"));
            table.AddCell(CreateSignatureFieldCell("sig3"));
            table.AddCell("For approval by Dave");
            table.AddCell(CreateTextFieldCell("approved_dave"));
            table.AddCell(CreateSignatureFieldCell("sig4"));
            doc.Add(table);

            doc.Close();
        }

        public void Certify(String keystore, String src, String name, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());

            // Set signer options
            signer.SetFieldName(name);
            signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);

            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
        }

        public void FillOut(String src, String dest, String name, String value)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
                new StampingProperties().UseAppendMode());

            PdfAcroForm form = PdfFormCreator.GetAcroForm(pdfDoc, true);
            form.GetField(name).SetValue(value);
            form.GetField(name).SetReadOnly(true);

            pdfDoc.Close();
        }

        public virtual void Sign(String keystore, String src, String name, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());
            signer.SetFieldName(name);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
            signer.SignDetached(pks, chain, null, null, null, 0,
                PdfSigner.CryptoStandard.CMS);
        }

        public void FillOutAndSign(String keystore, String src, String name, String fname,
            String value, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());
            signer.SetFieldName(name);

            PdfAcroForm form = PdfFormCreator.GetAcroForm(signer.GetDocument(), true);
            form.GetField(fname).SetValue(value);
            form.GetField(fname).SetReadOnly(true);

            IExternalSignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
            signer.SignDetached(pks, chain, null, null, null, 0,
                PdfSigner.CryptoStandard.CMS);
        }

        protected static Cell CreateTextFieldCell(String name)
        {
            Cell cell = new Cell();
            cell.SetHeight(20);
            cell.SetNextRenderer(new TextFieldCellRenderer(cell, name));
            return cell;
        }

        protected static Cell CreateSignatureFieldCell(String name)
        {
            Cell cell = new Cell();
            cell.SetHeight(50);
            cell.SetNextRenderer(new SignatureFieldCellRenderer(cell, name));
            return cell;
        }

        private class TextFieldCellRenderer : CellRenderer
        {
            public String name;

            public TextFieldCellRenderer(Cell modelElement, String name)
                : base(modelElement)
            {
                this.name = name;
            }

            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfFormField field = new TextFormFieldBuilder(drawContext.GetDocument(), name)
                    .SetWidgetRectangle(GetOccupiedAreaBBox()).CreateText();
                PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
            }
        }

        private class SignatureFieldCellRenderer : CellRenderer
        {
            public String name;

            public SignatureFieldCellRenderer(Cell modelElement, String name)
                : base(modelElement)
            {
                this.name = name;
            }

            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfFormField field = new SignatureFormFieldBuilder(drawContext.GetDocument(), name)
                    .SetWidgetRectangle(GetOccupiedAreaBBox()).CreateSignature();
                field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
                field.GetWidgets()[0].SetFlags(PdfAnnotation.PRINT);
                PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
            }
        }
    }
}

c2_12_lockfields

Locking fields and documents after signing:

JAVA

JAVA
package com.itextpdf.samples.signatures.chapter02;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.PdfSigFieldLock;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
import com.itextpdf.forms.fields.TextFormFieldBuilder;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

public class C2_12_LockFields {
    public static final String DEST = "./target/signatures/chapter02/";
    public static final String FORM = "./target/signatures/chapter02/form_lock.pdf";

    public static final String ALICE = "./src/test/resources/encryption/alice";
    public static final String BOB = "./src/test/resources/encryption/bob";
    public static final String CAROL = "./src/test/resources/encryption/carol";
    public static final String DAVE = "./src/test/resources/encryption/dave";
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";

    public static final char[] PASSWORD = "password".toCharArray();

    public static final String[] RESULT_FILES = new String[] {
            "step_1_signed_by_alice.pdf", "step_2_signed_by_alice_and_bob.pdf",
            "step_3_signed_by_alice_bob_and_carol.pdf", "step_4_signed_by_alice_bob_carol_and_dave.pdf",
            "step_5_signed_by_alice_and_bob_broken_by_chuck.pdf", "step_6_signed_by_dave_broken_by_chuck.pdf"
    };

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);

        C2_12_LockFields app = new C2_12_LockFields();
        app.createForm();

        app.certify(ALICE, provider.getName(), FORM, "sig1", DEST + RESULT_FILES[0]);
        app.fillOutAndSign(BOB, provider.getName(), DEST + RESULT_FILES[0], "sig2", "approved_bob",
                "Read and Approved by Bob", DEST + RESULT_FILES[1]);
        app.fillOutAndSign(CAROL, provider.getName(), DEST + RESULT_FILES[1], "sig3", "approved_carol",
                "Read and Approved by Carol", DEST + RESULT_FILES[2]);
        app.fillOutAndSign(DAVE, provider.getName(), DEST + RESULT_FILES[2], "sig4", "approved_dave",
                "Read and Approved by Dave", DEST + RESULT_FILES[3]);
        app.fillOut(DEST + RESULT_FILES[1], DEST + RESULT_FILES[4],
                "approved_bob", "Changed by Chuck");
        app.fillOut(DEST + RESULT_FILES[3], DEST + RESULT_FILES[5],
                "approved_carol", "Changed by Chuck");
    }

    public void createForm() throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
        Document doc = new Document(pdfDoc);

        Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
        table.addCell("Written by Alice");
        table.addCell(createSignatureFieldCell("sig1", null));
        table.addCell("For approval by Bob");
        table.addCell(createTextFieldCell("approved_bob"));

        PdfSigFieldLock lock = new PdfSigFieldLock()
                .setFieldLock(PdfSigFieldLock.LockAction.INCLUDE, "sig1", "approved_bob", "sig2");
        table.addCell(createSignatureFieldCell("sig2", lock));
        table.addCell("For approval by Carol");
        table.addCell(createTextFieldCell("approved_carol"));

        lock = new PdfSigFieldLock().setFieldLock(PdfSigFieldLock.LockAction.EXCLUDE, "approved_dave", "sig4");
        table.addCell(createSignatureFieldCell("sig3", lock));
        table.addCell("For approval by Dave");
        table.addCell(createTextFieldCell("approved_dave"));

        lock = new PdfSigFieldLock().setDocumentPermissions(PdfSigFieldLock.LockPermissions.NO_CHANGES_ALLOWED);
        table.addCell(createSignatureFieldCell("sig4", lock));
        doc.add(table);

        doc.close();
    }

    public void certify(String keystore, String provider, String src, String name, String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());

        // Set signer options
        signer.setFieldName(name);
        signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);

        PdfAcroForm form = PdfAcroForm.getAcroForm(signer.getDocument(), true);
        form.getField(name).setReadOnly(true);

        PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();

        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
    }

    public void fillOutAndSign(String keystore, String provider, String src, String name, String fname, String value,
            String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
        signer.setFieldName(name);

        PdfAcroForm form = PdfAcroForm.getAcroForm(signer.getDocument(), true);
        form.getField(fname).setValue(value);
        form.getField(name).setReadOnly(true);
        form.getField(fname).setReadOnly(true);

        PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
    }

    public void fillOut(String src, String dest, String name, String value) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
                new StampingProperties().useAppendMode());

        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
        form.getField(name).setValue(value);

        pdfDoc.close();
    }

    public void sign(String keystore, String provider, String src, String name, String dest)
            throws GeneralSecurityException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(keystore), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        Certificate[] chain = ks.getCertificateChain(alias);

        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode());
        signer.setFieldName(name);

        PrivateKeySignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider);
        IExternalDigest digest = new BouncyCastleDigest();
        signer.signDetached(digest, pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
    }

    protected static Cell createTextFieldCell(String name) {
        Cell cell = new Cell();
        cell.setHeight(20);
        cell.setNextRenderer(new TextFieldCellRenderer(cell, name));
        return cell;
    }

    protected static Cell createSignatureFieldCell(String name, PdfSigFieldLock lock) {
        Cell cell = new Cell();
        cell.setHeight(50);
        cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name, lock));
        return cell;
    }


    private static class TextFieldCellRenderer extends CellRenderer {
        public String name;

        public TextFieldCellRenderer(Cell modelElement, String name) {
            super(modelElement);
            this.name = name;
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfFormField field = new TextFormFieldBuilder(drawContext.getDocument(), name)
                    .setWidgetRectangle(getOccupiedAreaBBox()).createText();
            PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
        }
    }


    private static class SignatureFieldCellRenderer extends CellRenderer {
        public String name;
        public PdfSigFieldLock lock;

        public SignatureFieldCellRenderer(Cell modelElement, String name, PdfSigFieldLock lock) {
            super(modelElement);
            this.name = name;
            this.lock = lock;
        }

        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfFormField field = new SignatureFormFieldBuilder(drawContext.getDocument(), name)
                    .setWidgetRectangle(getOccupiedAreaBBox()).createSignature();
            if (lock != null) {
                field.put(PdfName.Lock, lock.makeIndirect(drawContext.getDocument()).getPdfObject());
            }

            field.getWidgets().get(0).setFlag(PdfAnnotation.PRINT);
            field.getWidgets().get(0).setHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
            PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(field);
        }
    }
}

C#

C#
using System;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Cert;
using Org.BouncyCastle.Crypto;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;

namespace iText.Samples.Signatures.Chapter02
{
    public class C2_12_LockFields
    {
        public static readonly string DEST = "results/signatures/chapter02/";
        public static readonly string FORM = "results/signatures/chapter02/form_lock.pdf";

        public static readonly string ALICE = "../../../resources/encryption/alice";
        public static readonly string BOB = "../../../resources/encryption/bob";
        public static readonly string CAROL = "../../../resources/encryption/carol";
        public static readonly string DAVE = "../../../resources/encryption/dave";
        public static readonly string KEYSTORE = "../../../resources/encryption/ks";

        public static readonly char[] PASSWORD = "password".ToCharArray();

        public static readonly String[] RESULT_FILES =
        {
            "step_1_signed_by_alice.pdf", "step_2_signed_by_alice_and_bob.pdf",
            "step_3_signed_by_alice_bob_and_carol.pdf", "step_4_signed_by_alice_bob_carol_and_dave.pdf",
            "step_5_signed_by_alice_and_bob_broken_by_chuck.pdf", "step_6_signed_by_dave_broken_by_chuck.pdf"
        };

        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();

            C2_12_LockFields app = new C2_12_LockFields();
            app.CreateForm();

            app.Certify(ALICE, FORM, "sig1", DEST + RESULT_FILES[0]);
            app.FillOutAndSign(BOB, DEST + RESULT_FILES[0], "sig2", "approved_bob",
                "Read and Approved by Bob", DEST + RESULT_FILES[1]);
            app.FillOutAndSign(CAROL, DEST + RESULT_FILES[1], "sig3", "approved_carol",
                "Read and Approved by Carol", DEST + RESULT_FILES[2]);
            app.FillOutAndSign(DAVE, DEST + RESULT_FILES[2], "sig4", "approved_dave",
                "Read and Approved by Dave", DEST + RESULT_FILES[3]);
            app.FillOut(DEST + RESULT_FILES[1], DEST + RESULT_FILES[4],
                "approved_bob", "Changed by Chuck");
            app.FillOut(DEST + RESULT_FILES[3], DEST + RESULT_FILES[5],
                "approved_carol", "Changed by Chuck");
        }

        public void CreateForm()
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
            Document doc = new Document(pdfDoc);

            Table table = new Table(1).UseAllAvailableWidth();
            table.AddCell("Written by Alice");
            table.AddCell(CreateSignatureFieldCell("sig1", null));
            table.AddCell("For approval by Bob");
            table.AddCell(CreateTextFieldCell("approved_bob"));

            PdfSigFieldLock Lock = new PdfSigFieldLock().SetFieldLock(PdfSigFieldLock.LockAction.INCLUDE,
                "sig1", "approved_bob", "sig2");
            table.AddCell(CreateSignatureFieldCell("sig2", Lock));
            table.AddCell("For approval by Carol");
            table.AddCell(CreateTextFieldCell("approved_carol"));

            Lock = new PdfSigFieldLock().SetFieldLock(PdfSigFieldLock.LockAction.EXCLUDE,
                "approved_dave", "sig4");
            table.AddCell(CreateSignatureFieldCell("sig3", Lock));
            table.AddCell("For approval by Dave");
            table.AddCell(CreateTextFieldCell("approved_dave"));

            Lock = new PdfSigFieldLock().SetDocumentPermissions(PdfSigFieldLock.LockPermissions.NO_CHANGES_ALLOWED);
            table.AddCell(CreateSignatureFieldCell("sig4", Lock));
            doc.Add(table);

            doc.Close();
        }

        public void Certify(String keystore, String src, String name, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());

            // Set signer options
            signer.SetFieldName(name);
            signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);

            PdfAcroForm form = PdfFormCreator.GetAcroForm(signer.GetDocument(), true);
            form.GetField(name).SetReadOnly(true);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);

            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
        }

        public void FillOutAndSign(String keystore, String src, String name, String fname, String value, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());
            signer.SetFieldName(name);

            PdfAcroForm form = PdfFormCreator.GetAcroForm(signer.GetDocument(), true);
            form.GetField(fname).SetValue(value);
            form.GetField(name).SetReadOnly(true);
            form.GetField(fname).SetReadOnly(true);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
            signer.SignDetached(pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
        }

        public void FillOut(String src, String dest, String name, String value)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest),
                new StampingProperties().UseAppendMode());

            PdfAcroForm form = PdfFormCreator.GetAcroForm(pdfDoc, true);
            form.GetField(name).SetValue(value);

            pdfDoc.Close();
        }

        public void Sign(String keystore, String src, String name, String dest)
        {
            Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build();
            pk12.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            IX509Certificate[] chain = new IX509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = new X509CertificateBC(ce[k].Certificate);
            }

            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create),
                new StampingProperties().UseAppendMode());
            signer.SetFieldName(name);

            PrivateKeySignature pks = new PrivateKeySignature(new PrivateKeyBC(pk), DigestAlgorithms.SHA256);
            signer.SignDetached(pks, chain, null, null, null,
                0, PdfSigner.CryptoStandard.CMS);
        }

        protected static Cell CreateTextFieldCell(String name)
        {
            Cell cell = new Cell();
            cell.SetHeight(20);
            cell.SetNextRenderer(new TextFieldCellRenderer(cell, name));
            return cell;
        }

        protected static Cell CreateSignatureFieldCell(String name, PdfSigFieldLock Lock)
        {
            Cell cell = new Cell();
            cell.SetHeight(50);
            cell.SetNextRenderer(new SignatureFieldCellRenderer(cell, name, Lock));
            return cell;
        }

        private class TextFieldCellRenderer : CellRenderer
        {
            public String name;

            public TextFieldCellRenderer(Cell modelElement, String name)
                : base(modelElement)
            {
                this.name = name;
            }

            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfFormField field = new TextFormFieldBuilder(drawContext.GetDocument(), name)
                    .SetWidgetRectangle(GetOccupiedAreaBBox()).CreateText();
                PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
            }
        }

        private class SignatureFieldCellRenderer : CellRenderer
        {
            public String name;
            public PdfSigFieldLock Lock;

            public SignatureFieldCellRenderer(Cell modelElement, String name, PdfSigFieldLock Lock)
                : base(modelElement)
            {
                this.name = name;
                this.Lock = Lock;
            }

            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfFormField field = new SignatureFormFieldBuilder(drawContext.GetDocument(), name)
                    .SetWidgetRectangle(GetOccupiedAreaBBox()).CreateSignature();
                if (Lock != null)
                {
                    field.Put(PdfName.Lock, this.Lock.MakeIndirect(drawContext.GetDocument()).GetPdfObject());
                }

                field.GetWidgets()[0].SetFlag(PdfAnnotation.PRINT);
                field.GetWidgets()[0].SetHighlightMode(PdfAnnotation.HIGHLIGHT_INVERT);
                PdfFormCreator.GetAcroForm(drawContext.GetDocument(), true).AddField(field);
            }
        }
    }
}

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.