Skip to main content
Skip table of contents

Digital signatures - chapter 5

These examples were written in the context of Chapter 5 - "Validation of signed documents" of the Digital Signatures for PDF documents eBook.


c5_01_signatureintegrity

Checking the validity of a signature:

JAVA

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

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.signatures.PdfPKCS7;
import com.itextpdf.signatures.SignatureUtil;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.Security;
import java.util.List;

public class C5_01_SignatureIntegrity {
    public static final String DEST = "./target/test/resources/signatures/chapter05/";

    public static final String EXAMPLE1 = "./src/test/resources/pdfs/hello_level_1_annotated.pdf";
    public static final String EXAMPLE2 = "./src/test/resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf";
    public static final String EXAMPLE3 = "./src/test/resources/pdfs/step_6_signed_by_dave_broken_by_chuck.pdf";

    public static final String EXPECTED_OUTPUT = "./src/test/resources/pdfs/hello_level_1_annotated.pdf\n" +
            "===== sig =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 1 of 2\n" +
            "Integrity check OK? true\n" +
            "./src/test/resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf\n" +
            "===== sig1 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 1 of 4\n" +
            "Integrity check OK? true\n" +
            "===== sig2 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 2 of 4\n" +
            "Integrity check OK? true\n" +
            "===== sig3 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 3 of 4\n" +
            "Integrity check OK? true\n" +
            "===== sig4 =====\n" +
            "Signature covers whole document: true\n" +
            "Document revision: 4 of 4\n" +
            "Integrity check OK? true\n" +
            "./src/test/resources/pdfs/step_6_signed_by_dave_broken_by_chuck.pdf\n" +
            "===== sig1 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 1 of 5\n" +
            "Integrity check OK? true\n" +
            "===== sig2 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 2 of 5\n" +
            "Integrity check OK? true\n" +
            "===== sig3 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 3 of 5\n" +
            "Integrity check OK? true\n" +
            "===== sig4 =====\n" +
            "Signature covers whole document: false\n" +
            "Document revision: 4 of 5\n" +
            "Integrity check OK? true\n";

    public void verifySignatures(String path) throws IOException, GeneralSecurityException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(path));
        SignatureUtil signUtil = new SignatureUtil(pdfDoc);
        List<String> names = signUtil.getSignatureNames();

        System.out.println(path);
        for (String name : names) {
            System.out.println("===== " + name + " =====");
            verifySignature(signUtil, name);
        }

        pdfDoc.close();
    }

    public PdfPKCS7 verifySignature(SignatureUtil signUtil, String name) throws GeneralSecurityException {
        PdfPKCS7 pkcs7 = signUtil.readSignatureData(name);

        System.out.println("Signature covers whole document: " + signUtil.signatureCoversWholeDocument(name));
        System.out.println("Document revision: " + signUtil.getRevision(name) + " of " + signUtil.getTotalRevisions());
        System.out.println("Integrity check OK? " + pkcs7.verifySignatureIntegrityAndAuthenticity());

        return pkcs7;
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);

        C5_01_SignatureIntegrity app = new C5_01_SignatureIntegrity();
        app.verifySignatures(EXAMPLE1);
        app.verifySignatures(EXAMPLE2);
        app.verifySignatures(EXAMPLE3);
    }
}

C#

C#
using System;
using System.Collections.Generic;
using iText.Kernel.Pdf;
using iText.Signatures;

namespace iText.Samples.Signatures.Chapter05
{
    public class C5_01_SignatureIntegrity
    {
        public static readonly string DEST = "signatures/chapter05/";
        
        public static readonly string EXAMPLE1 = "../../../resources/pdfs/hello_level_1_annotated.pdf";

        public static readonly string EXAMPLE2 = "../../../resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf";

        public static readonly string EXAMPLE3 = "../../../resources/pdfs/step_6_signed_by_dave_broken_by_chuck.pdf";

        public const String EXPECTED_OUTPUT = "../../../resources/pdfs/hello_level_1_annotated.pdf\n"
                                             + "===== sig =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 1 of 2\n"
                                             + "Integrity check OK? True\n"
                                             + "../../../resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf\n"
                                             + "===== sig1 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 1 of 4\n"
                                             + "Integrity check OK? True\n"
                                             + "===== sig2 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 2 of 4\n"
                                             + "Integrity check OK? True\n"
                                             + "===== sig3 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 3 of 4\n"
                                             + "Integrity check OK? True\n"
                                             + "===== sig4 =====\n"
                                             + "Signature covers whole document: True\n"
                                             + "Document revision: 4 of 4\n"
                                             + "Integrity check OK? True\n"
                                             + "../../../resources/pdfs/step_6_signed_by_dave_broken_by_chuck.pdf\n"
                                             + "===== sig1 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 1 of 5\n"
                                             + "Integrity check OK? True\n"
                                             + "===== sig2 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 2 of 5\n"
                                             + "Integrity check OK? True\n"
                                             + "===== sig3 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 3 of 5\n"
                                             + "Integrity check OK? True\n"
                                             + "===== sig4 =====\n"
                                             + "Signature covers whole document: False\n"
                                             + "Document revision: 4 of 5\n"
                                             + "Integrity check OK? True\n";

        public void VerifySignatures(String path)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(path));
            SignatureUtil signUtil = new SignatureUtil(pdfDoc);
            IList<String> names = signUtil.GetSignatureNames();

            Console.WriteLine(path);
            foreach (String name in names)
            {
                Console.Out.WriteLine("===== " + name + " =====");
                VerifySignature(signUtil, name);
            }
            
            pdfDoc.Close();
        }

        public PdfPKCS7 VerifySignature(SignatureUtil signUtil, String name)
        {
            PdfPKCS7 pkcs7 = signUtil.ReadSignatureData(name);

            Console.Out.WriteLine("Signature covers whole document: " + signUtil.SignatureCoversWholeDocument(name));
            Console.Out.WriteLine("Document revision: " + signUtil.GetRevision(name) + " of "
                                  + signUtil.GetTotalRevisions());
            Console.Out.WriteLine("Integrity check OK? " + pkcs7.VerifySignatureIntegrityAndAuthenticity());
            return pkcs7;
        }

        public static void Main(String[] args)
        {
            C5_01_SignatureIntegrity app = new C5_01_SignatureIntegrity();
            app.VerifySignatures(EXAMPLE1);
            app.VerifySignatures(EXAMPLE2);
            app.VerifySignatures(EXAMPLE3);
        }
    }
}


c5_02_signatureinfo

Retrieving information from a signature:

JAVA

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

import com.itextpdf.bouncycastle.asn1.tsp.TSTInfoBC;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation;
import com.itextpdf.signatures.CertificateInfo;
import com.itextpdf.signatures.PdfPKCS7;
import com.itextpdf.signatures.SignaturePermissions;
import com.itextpdf.signatures.SignatureUtil;
import com.itextpdf.signatures.TimestampConstants;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.List;
import org.bouncycastle.asn1.tsp.TSTInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class C5_02_SignatureInfo {
    public static final String DEST = "./target/test/resources/signatures/chapter05/";

    public static final String EXAMPLE1 = "./src/test/resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf";
    public static final String EXAMPLE2 = "./src/test/resources/pdfs/hello_signed4.pdf";
    public static final String EXAMPLE3 = "./src/test/resources/pdfs/field_metadata.pdf";

    public static final String EXPECTED_OUTPUT =
            "./src/test/resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf\n" +
                    "===== sig1 =====\n" +
                    "Field on page 1; llx: 36.0, lly: 728.02, urx: 559.0; ury: 779.02\n" +
                    "Signature covers whole document: false\n" +
                    "Document revision: 1 of 4\n" +
                    "Integrity check OK? true\n" +
                    "Digest algorithm: SHA256\n" +
                    "Encryption algorithm: RSA\n" +
                    "Filter subtype: /adbe.pkcs7.detached\n" +
                    "Name of the signer: Alice Specimen\n" +
                    "Signed on: 2016-02-23\n" +
                    "Location: \n" +
                    "Reason: \n" +
                    "Contact info: \n" +
                    "Signature type: certification\n" +
                    "Filling out fields allowed: true\n" +
                    "Adding annotations allowed: false\n" +
                    "===== sig2 =====\n" +
                    "Field on page 1; llx: 36.0, lly: 629.04, urx: 559.0; ury: 680.04\n" +
                    "Signature covers whole document: false\n" +
                    "Document revision: 2 of 4\n" +
                    "Integrity check OK? true\n" +
                    "Digest algorithm: SHA256\n" +
                    "Encryption algorithm: RSA\n" +
                    "Filter subtype: /adbe.pkcs7.detached\n" +
                    "Name of the signer: Bob Specimen\n" +
                    "Signed on: 2016-02-23\n" +
                    "Location: \n" +
                    "Reason: \n" +
                    "Contact info: \n" +
                    "Signature type: approval\n" +
                    "Filling out fields allowed: true\n" +
                    "Adding annotations allowed: false\n" +
                    "Lock: /Include[sig1 approved_bob sig2 ]\n" +
                    "===== sig3 =====\n" +
                    "Field on page 1; llx: 36.0, lly: 530.05, urx: 559.0; ury: 581.05\n" +
                    "Signature covers whole document: false\n" +
                    "Document revision: 3 of 4\n" +
                    "Integrity check OK? true\n" +
                    "Digest algorithm: SHA256\n" +
                    "Encryption algorithm: RSA\n" +
                    "Filter subtype: /adbe.pkcs7.detached\n" +
                    "Name of the signer: Carol Specimen\n" +
                    "Signed on: 2016-02-23\n" +
                    "Location: \n" +
                    "Reason: \n" +
                    "Contact info: \n" +
                    "Signature type: approval\n" +
                    "Filling out fields allowed: true\n" +
                    "Adding annotations allowed: false\n" +
                    "Lock: /Include[sig1 approved_bob sig2 ]\n" +
                    "Lock: /Exclude[approved_dave sig4 ]\n" +
                    "===== sig4 =====\n" +
                    "Field on page 1; llx: 36.0, lly: 431.07, urx: 559.0; ury: 482.07\n" +
                    "Signature covers whole document: true\n" +
                    "Document revision: 4 of 4\n" +
                    "Integrity check OK? true\n" +
                    "Digest algorithm: SHA256\n" +
                    "Encryption algorithm: RSA\n" +
                    "Filter subtype: /adbe.pkcs7.detached\n" +
                    "Name of the signer: Dave Specimen\n" +
                    "Signed on: 2016-02-23\n" +
                    "Location: \n" +
                    "Reason: \n" +
                    "Contact info: \n" +
                    "Signature type: approval\n" +
                    "Filling out fields allowed: false\n" +
                    "Adding annotations allowed: false\n" +
                    "Lock: /Include[sig1 approved_bob sig2 ]\n" +
                    "Lock: /Exclude[approved_dave sig4 ]\n" +
                    "./src/test/resources/pdfs/hello_signed4.pdf\n" +
                    "===== sig =====\n" +
                    "Field on page 1; llx: 36.0, lly: 648.0, urx: 236.0; ury: 748.0\n" +
                    "Signature covers whole document: true\n" +
                    "Document revision: 1 of 1\n" +
                    "Integrity check OK? true\n" +
                    "Digest algorithm: RIPEMD160\n" +
                    "Encryption algorithm: RSA\n" +
                    "Filter subtype: /ETSI.CAdES.detached\n" +
                    "Name of the signer: Bruno Specimen\n" +
                    "Signed on: 2016-02-23\n" +
                    "Location: Ghent\n" +
                    "Reason: Test 4\n" +
                    "Contact info: \n" +
                    "Signature type: approval\n" +
                    "Filling out fields allowed: true\n" +
                    "Adding annotations allowed: true\n" +
                    "./src/test/resources/pdfs/field_metadata.pdf\n" +
                    "===== Signature1 =====\n" +
                    "Field on page 1; llx: 46.0674, lly: 472.172, urx: 332.563; ury: 726.831\n" +
                    "Signature covers whole document: true\n" +
                    "Document revision: 1 of 1\n" +
                    "Integrity check OK? true\n" +
                    "Digest algorithm: SHA256\n" +
                    "Encryption algorithm: RSA\n" +
                    "Filter subtype: /adbe.pkcs7.detached\n" +
                    "Name of the signer: Bruno Specimen\n" +
                    "Alternative name of the signer: Bruno L. Specimen\n" +
                    "Signed on: 2016-02-23\n" +
                    "Location: Ghent\n" +
                    "Reason: Test metadata\n" +
                    "Contact info: 555 123 456\n" +
                    "Signature type: approval\n" +
                    "Filling out fields allowed: true\n" +
                    "Adding annotations allowed: true\n";

    public SignaturePermissions inspectSignature(PdfDocument pdfDoc, SignatureUtil signUtil, PdfAcroForm form,
            String name, SignaturePermissions perms) throws GeneralSecurityException {
        List<PdfWidgetAnnotation> widgets = form.getField(name).getWidgets();

        // Check the visibility of the signature annotation
        if (widgets != null && widgets.size() > 0) {
            Rectangle pos = widgets.get(0).getRectangle().toRectangle();
            int pageNum = pdfDoc.getPageNumber(widgets.get(0).getPage());
            if (pos.getWidth() == 0 || pos.getHeight() == 0) {
                System.out.println("Invisible signature");
            } else {
                System.out.println(String.format("Field on page %s; llx: %s, lly: %s, urx: %s; ury: %s",
                        pageNum, pos.getLeft(), pos.getBottom(), pos.getRight(), pos.getTop()));
            }
        }

        /* Find out how the message digest of the PDF bytes was created,
         * how these bytes and additional attributes were signed
         * and how the signed bytes are stored in the PDF
         */
        PdfPKCS7 pkcs7 = verifySignature(signUtil, name);
        System.out.println("Digest algorithm: " + pkcs7.getDigestAlgorithmName());
        System.out.println("Encryption algorithm: " + pkcs7.getSignatureAlgorithmName());
        System.out.println("Filter subtype: " + pkcs7.getFilterSubtype());

        // Get the signing certificate to find out the name of the signer.
        X509Certificate cert = (X509Certificate) pkcs7.getSigningCertificate();
        System.out.println("Name of the signer: " + CertificateInfo.getSubjectFields(cert).getField("CN"));
        if (pkcs7.getSignName() != null) {
            System.out.println("Alternative name of the signer: " + pkcs7.getSignName());
        }

        // Get the signing time
        SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd");

        /* Mind that the getSignDate() method is not that secure as timestamp
         * because it's based only on signature author claim. I.e. this value can only be trusted
         * if signature is trusted and it cannot be used for signature verification.
         */
        System.out.println("Signed on: " + date_format.format(pkcs7.getSignDate().getTime()));

        /* If a timestamp was applied, retrieve information about it.
         * Timestamp is a secure source of signature creation time,
         * because it's based on Time Stamping Authority service.
         */
        if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE != pkcs7.getTimeStampDate()) {
            System.out.println("TimeStamp: " + date_format.format(pkcs7.getTimeStampDate().getTime()));
            TSTInfo ts = ((TSTInfoBC) pkcs7.getTimeStampTokenInfo()).getTstInfo();
            System.out.println("TimeStamp service: " + ts.getTsa());
            System.out.println("Timestamp verified? " + pkcs7.verifyTimestampImprint());
        }

        System.out.println("Location: " + pkcs7.getLocation());
        System.out.println("Reason: " + pkcs7.getReason());

        /* If you want less common entries than PdfPKCS7 object has, such as the contact info,
         * you should use the signature dictionary and get the properties by name.
         */
        PdfDictionary sigDict = signUtil.getSignatureDictionary(name);
        PdfString contact = sigDict.getAsString(PdfName.ContactInfo);
        if (contact != null) {
            System.out.println("Contact info: " + contact);
        }

        /* Every new signature can add more restrictions to a document, but it can't take away previous restrictions.
         * So if you want to retrieve information about signatures restrictions, you need to pass
         * the SignaturePermissions instance of the previous signature, or null if there was none.
         */
        perms = new SignaturePermissions(sigDict, perms);
        System.out.println("Signature type: " + (perms.isCertification() ? "certification" : "approval"));
        System.out.println("Filling out fields allowed: " + perms.isFillInAllowed());
        System.out.println("Adding annotations allowed: " + perms.isAnnotationsAllowed());
        for (SignaturePermissions.FieldLock lock : perms.getFieldLocks()) {
            System.out.println("Lock: " + lock.toString());
        }

        return perms;
    }

    public PdfPKCS7 verifySignature(SignatureUtil signUtil, String name) throws GeneralSecurityException {
        PdfPKCS7 pkcs7 = signUtil.readSignatureData(name);

        System.out.println("Signature covers whole document: " + signUtil.signatureCoversWholeDocument(name));
        System.out.println("Document revision: " + signUtil.getRevision(name) + " of " + signUtil.getTotalRevisions());
        System.out.println("Integrity check OK? " + pkcs7.verifySignatureIntegrityAndAuthenticity());

        return pkcs7;
    }

    public void inspectSignatures(String path) throws IOException, GeneralSecurityException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(path));
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);
        SignaturePermissions perms = null;
        SignatureUtil signUtil = new SignatureUtil(pdfDoc);
        List<String> names = signUtil.getSignatureNames();

        System.out.println(path);
        for (String name : names) {
            System.out.println("===== " + name + " =====");
            perms = inspectSignature(pdfDoc, signUtil, form, name, perms);
        }
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);

        C5_02_SignatureInfo app = new C5_02_SignatureInfo();
        app.inspectSignatures(EXAMPLE1);
        app.inspectSignatures(EXAMPLE2);
        app.inspectSignatures(EXAMPLE3);
    }
}

C#

C#
using System;
using System.Collections.Generic;
using iText.Bouncycastle.Asn1.Tsp;
using iText.Commons.Bouncycastle.Cert;
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Annot;
using iText.Signatures;

namespace iText.Samples.Signatures.Chapter05
{
    public class C5_02_SignatureInfo
    {
        public static readonly string DEST = "signatures/chapter05/";

        public static readonly string EXAMPLE1 = "../../../resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf";
        public static readonly string EXAMPLE2 = "../../../resources/pdfs/hello_signed4.pdf";
        public static readonly string EXAMPLE3 = "../../../resources/pdfs/field_metadata.pdf";

        public const String EXPECTED_OUTPUT = "../../../resources/pdfs/step_4_signed_by_alice_bob_carol_and_dave.pdf\n"
                                              + "===== sig1 =====\n"
                                              + "Field on page 1; llx: 36, lly: 728.02, urx: 559; ury: 779.02\n"
                                              + "Signature covers whole document: False\n"
                                              + "Document revision: 1 of 4\n"
                                              + "Integrity check OK? True\n"
                                              + "Digest algorithm: SHA256\n"
                                              + "Encryption algorithm: RSA\n"
                                              + "Filter subtype: /adbe.pkcs7.detached\n"
                                              + "Name of the signer: Alice Specimen\n"
                                              + "Signed on: 2016-02-23\n"
                                              + "Location: \n"
                                              + "Reason: \n"
                                              + "Contact info: \n"
                                              + "Signature type: certification\n"
                                              + "Filling out fields allowed: True\n"
                                              + "Adding annotations allowed: False\n"
                                              + "===== sig2 =====\n"
                                              + "Field on page 1; llx: 36, lly: 629.04, urx: 559; ury: 680.04\n"
                                              + "Signature covers whole document: False\n"
                                              + "Document revision: 2 of 4\n"
                                              + "Integrity check OK? True\n"
                                              + "Digest algorithm: SHA256\n"
                                              + "Encryption algorithm: RSA\n"
                                              + "Filter subtype: /adbe.pkcs7.detached\n"
                                              + "Name of the signer: Bob Specimen\n"
                                              + "Signed on: 2016-02-23\n"
                                              + "Location: \n"
                                              + "Reason: \n"
                                              + "Contact info: \n"
                                              + "Signature type: approval\n"
                                              + "Filling out fields allowed: True\n"
                                              + "Adding annotations allowed: False\n"
                                              + "Lock: /Include[sig1 approved_bob sig2 ]\n"
                                              + "===== sig3 =====\n"
                                              + "Field on page 1; llx: 36, lly: 530.05, urx: 559; ury: 581.05\n"
                                              + "Signature covers whole document: False\n"
                                              + "Document revision: 3 of 4\n"
                                              + "Integrity check OK? True\n"
                                              + "Digest algorithm: SHA256\n"
                                              + "Encryption algorithm: RSA\n"
                                              + "Filter subtype: /adbe.pkcs7.detached\n"
                                              + "Name of the signer: Carol Specimen\n"
                                              + "Signed on: 2016-02-23\n"
                                              + "Location: \n"
                                              + "Reason: \n"
                                              + "Contact info: \n"
                                              + "Signature type: approval\n"
                                              + "Filling out fields allowed: True\n"
                                              + "Adding annotations allowed: False\n"
                                              + "Lock: /Include[sig1 approved_bob sig2 ]\n"
                                              + "Lock: /Exclude[approved_dave sig4 ]\n"
                                              + "===== sig4 =====\n"
                                              + "Field on page 1; llx: 36, lly: 431.07, urx: 559; ury: 482.07\n"
                                              + "Signature covers whole document: True\n"
                                              + "Document revision: 4 of 4\n"
                                              + "Integrity check OK? True\n"
                                              + "Digest algorithm: SHA256\n"
                                              + "Encryption algorithm: RSA\n"
                                              + "Filter subtype: /adbe.pkcs7.detached\n"
                                              + "Name of the signer: Dave Specimen\n"
                                              + "Signed on: 2016-02-23\n"
                                              + "Location: \n"
                                              + "Reason: \n"
                                              + "Contact info: \n"
                                              + "Signature type: approval\n"
                                              + "Filling out fields allowed: False\n"
                                              + "Adding annotations allowed: False\n"
                                              + "Lock: /Include[sig1 approved_bob sig2 ]\n"
                                              + "Lock: /Exclude[approved_dave sig4 ]\n"
                                              + "../../../resources/pdfs/hello_signed4.pdf\n"
                                              + "===== sig =====\n"
                                              + "Field on page 1; llx: 36, lly: 648, urx: 236; ury: 748\n"
                                              + "Signature covers whole document: True\n"
                                              + "Document revision: 1 of 1\n"
                                              + "Integrity check OK? True\n"
                                              + "Digest algorithm: RIPEMD160\n"
                                              + "Encryption algorithm: RSA\n"
                                              + "Filter subtype: /ETSI.CAdES.detached\n"
                                              + "Name of the signer: Bruno Specimen\n"
                                              + "Signed on: 2016-02-23\n"
                                              + "Location: Ghent\n"
                                              + "Reason: Test 4\n"
                                              + "Contact info: \n"
                                              + "Signature type: approval\n"
                                              + "Filling out fields allowed: True\n"
                                              + "Adding annotations allowed: True\n"
                                              + "../../../resources/pdfs/field_metadata.pdf\n"
                                              + "===== Signature1 =====\n"
                                              + "Field on page 1; llx: 46.0674, lly: 472.172, urx: 332.563; ury: 726.831\n"
                                              + "Signature covers whole document: True\n"
                                              + "Document revision: 1 of 1\n"
                                              + "Integrity check OK? True\n"
                                              + "Digest algorithm: SHA256\n"
                                              + "Encryption algorithm: RSA\n"
                                              + "Filter subtype: /adbe.pkcs7.detached\n"
                                              + "Name of the signer: Bruno Specimen\n"
                                              + "Alternative name of the signer: Bruno L. Specimen\n"
                                              + "Signed on: 2016-02-23\n"
                                              + "Location: Ghent\n"
                                              + "Reason: Test metadata\n"
                                              + "Contact info: 555 123 456\n"
                                              + "Signature type: approval\n"
                                              + "Filling out fields allowed: True\n"
                                              + "Adding annotations allowed: True\n";

        public SignaturePermissions InspectSignature(PdfDocument pdfDoc, SignatureUtil signUtil, PdfAcroForm form,
            String name, SignaturePermissions perms)
        {
            IList<PdfWidgetAnnotation> widgets = form.GetField(name).GetWidgets();

            // Check the visibility of the signature annotation
            if (widgets != null && widgets.Count > 0)
            {
                Rectangle pos = widgets[0].GetRectangle().ToRectangle();
                int pageNum = pdfDoc.GetPageNumber(widgets[0].GetPage());

                if (pos.GetWidth() == 0 || pos.GetHeight() == 0)
                {
                    Console.Out.WriteLine("Invisible signature");
                }
                else
                {
                    Console.Out.WriteLine(String.Format("Field on page {0}; llx: {1}, lly: {2}, urx: {3}; ury: {4}",
                        pageNum, pos.GetLeft(), pos.GetBottom(), pos.GetRight(), pos.GetTop()));
                }
            }

            /* Find out how the message digest of the PDF bytes was created,
             * how these bytes and additional attributes were signed
             * and how the signed bytes are stored in the PDF
             */
            PdfPKCS7 pkcs7 = VerifySignature(signUtil, name);
            Console.Out.WriteLine("Digest algorithm: " + pkcs7.GetDigestAlgorithmName());
            Console.Out.WriteLine("Encryption algorithm: " + pkcs7.GetSignatureAlgorithmName());
            Console.Out.WriteLine("Filter subtype: " + pkcs7.GetFilterSubtype());

            // Get the signing certificate to find out the name of the signer.
            IX509Certificate cert = pkcs7.GetSigningCertificate();
            Console.Out.WriteLine("Name of the signer: "
                                  + iText.Signatures.CertificateInfo.GetSubjectFields(cert).GetField("CN"));
            if (pkcs7.GetSignName() != null)
            {
                Console.Out.WriteLine("Alternative name of the signer: " + pkcs7.GetSignName());
            }

            /* Get the signing time.
             * Mind that the getSignDate() method is not that secure as timestamp
             * because it's based only on signature author claim. I.e. this value can only be trusted
             * if signature is trusted and it cannot be used for signature verification.
             */
            Console.Out.WriteLine("Signed on: " + pkcs7.GetSignDate().ToUniversalTime().ToString("yyyy-MM-dd"));

            /* If a timestamp was applied, retrieve information about it.
             * Timestamp is a secure source of signature creation time,
             * because it's based on Time Stamping Authority service.
             */
            if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE != pkcs7.GetTimeStampDate())
            {
                Console.Out.WriteLine("TimeStamp: " +
                                      pkcs7.GetTimeStampDate().ToUniversalTime().ToString("yyyy-MM-dd"));
                TstInfoBC ts = (TstInfoBC)pkcs7.GetTimeStampTokenInfo();
                Console.Out.WriteLine("TimeStamp service: " + ts.GetTstInfo().Tsa);
                Console.Out.WriteLine("Timestamp verified? " + pkcs7.VerifyTimestampImprint());
            }

            Console.Out.WriteLine("Location: " + pkcs7.GetLocation());
            Console.Out.WriteLine("Reason: " + pkcs7.GetReason());

            /* If you want less common entries than PdfPKCS7 object has, such as the contact info,
             * you should use the signature dictionary and get the properties by name.
             */
            PdfDictionary sigDict = signUtil.GetSignatureDictionary(name);
            PdfString contact = sigDict.GetAsString(PdfName.ContactInfo);
            if (contact != null)
            {
                Console.Out.WriteLine("Contact info: " + contact);
            }

            /* Every new signature can add more restrictions to a document, but it can’t take away previous restrictions.
             * So if you want to retrieve information about signatures restrictions, you need to pass
             * the SignaturePermissions instance of the previous signature, or null if there was none.
             */
            perms = new SignaturePermissions(sigDict, perms);
            Console.Out.WriteLine("Signature type: " + (perms.IsCertification() ? "certification" : "approval"));
            Console.Out.WriteLine("Filling out fields allowed: " + perms.IsFillInAllowed());
            Console.Out.WriteLine("Adding annotations allowed: " + perms.IsAnnotationsAllowed());
            foreach (SignaturePermissions.FieldLock Lock in perms.GetFieldLocks())
            {
                Console.Out.WriteLine("Lock: " + Lock);
            }

            return perms;
        }

        public PdfPKCS7 VerifySignature(SignatureUtil signUtil, String name)
        {
            PdfPKCS7 pkcs7 = signUtil.ReadSignatureData(name);

            Console.Out.WriteLine("Signature covers whole document: " + signUtil.SignatureCoversWholeDocument(name));
            Console.Out.WriteLine("Document revision: " + signUtil.GetRevision(name) + " of "
                                  + signUtil.GetTotalRevisions());
            Console.Out.WriteLine("Integrity check OK? " + pkcs7.VerifySignatureIntegrityAndAuthenticity());
            return pkcs7;
        }

        public virtual void InspectSignatures(String path)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(path));
            PdfAcroForm form = PdfFormCreator.GetAcroForm(pdfDoc, false);
            SignaturePermissions perms = null;
            SignatureUtil signUtil = new SignatureUtil(pdfDoc);
            IList<String> names = signUtil.GetSignatureNames();

            Console.WriteLine(path);
            foreach (String name in names)
            {
                Console.Out.WriteLine("===== " + name + " =====");
                perms = InspectSignature(pdfDoc, signUtil, form, name, perms);
            }
        }

        public static void Main(String[] args)
        {
            C5_02_SignatureInfo app = new C5_02_SignatureInfo();
            app.InspectSignatures(EXAMPLE1);
            app.InspectSignatures(EXAMPLE2);
            app.InspectSignatures(EXAMPLE3);
        }
    }
}

c5_03_certificatevalidation

Validating the certificates of a signature:

JAVA

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

import com.itextpdf.bouncycastle.cert.ocsp.BasicOCSPRespBC;
import com.itextpdf.commons.bouncycastle.cert.ocsp.IBasicOCSPResp;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.signatures.CRLVerifier;
import com.itextpdf.signatures.CertificateVerification;
import com.itextpdf.signatures.OCSPVerifier;
import com.itextpdf.signatures.PdfPKCS7;
import com.itextpdf.signatures.SignatureUtil;
import com.itextpdf.signatures.TimestampConstants;
import com.itextpdf.signatures.VerificationException;
import com.itextpdf.signatures.VerificationOK;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.CRL;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.LoggerFactory;

public class C5_03_CertificateValidation {
    public static final String DEST = "./target/test/resources/signatures/chapter05/";

    public static final String ROOT = "./src/test/resources/encryption/rootRsa.cer";

    public static final String EXAMPLE = "./src/test/resources/pdfs/signedPAdES-LT.pdf";

    public static final String EXPECTED_OUTPUT = "./src/test/resources/pdfs/signedPAdES-LT.pdf\n"
            + "===== Signature1 =====\n"
            + "Signature covers whole document: false\n"
            + "Document revision: 1 of 2\n"
            + "Integrity check OK? true\n"
            + "Certificates verified against the KeyStore\n"
            + "=== Certificate 0 ===\n"
            + "Issuer: CN=iTextTestRoot, OU=test, O=iText, L=Minsk, C=BY\n"
            + "Subject: CN=iTextTestRsaCert01, OU=test, O=iText, L=Minsk, C=BY\n"
            + "Valid from: 2017-04-07-15-33\n"
            + "Valid to: 2117-04-07-15-33\n"
            + "The certificate was valid at the time of signing.\n"
            + "The certificate is still valid.\n"
            + "=== Certificate 1 ===\n"
            + "Issuer: CN=iTextTestRoot, OU=test, O=iText, L=Minsk, C=BY\n"
            + "Subject: CN=iTextTestRoot, OU=test, O=iText, L=Minsk, C=BY\n"
            + "Valid from: 2017-04-07-13-20\n"
            + "Valid to: 2117-04-07-13-20\n"
            + "The certificate was valid at the time of signing.\n"
            + "The certificate is still valid.\n"
            + "=== Checking validity of the document at the time of signing ===\n"
            + "com.itextpdf.signatures.OCSPVerifier INFO Valid OCSPs found: 0\n"
            + "com.itextpdf.signatures.CRLVerifier INFO Valid CRLs found: 0\n"
            + "The signing certificate couldn't be verified\n"
            + "=== Checking validity of the document today ===\n"
            + "com.itextpdf.signatures.OCSPVerifier INFO Valid OCSPs found: 0\n"
            + "com.itextpdf.signatures.CRLVerifier INFO Valid CRLs found: 0\n"
            + "The signing certificate couldn't be verified"
            +"\n";

    private static PrintStream OUT_STREAM = System.out;
    private static AppenderBase<ILoggingEvent> appender;
    private KeyStore ks;

    public void verifySignatures(String path) throws IOException, GeneralSecurityException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(path));
        SignatureUtil signUtil = new SignatureUtil(pdfDoc);
        List<String> names = signUtil.getSignatureNames();

        OUT_STREAM.println(path);
        for (String name : names) {
            OUT_STREAM.println("===== " + name + " =====");
            verifySignature(signUtil, name);
        }
    }

    public PdfPKCS7 verifySignature(SignatureUtil signUtil, String name) throws GeneralSecurityException,
            IOException {
        PdfPKCS7 pkcs7 = getSignatureData(signUtil, name);
        Certificate[] certs = pkcs7.getSignCertificateChain();

        // Timestamp is a secure source of signature creation time,
        // because it's based on Time Stamping Authority service.
        Calendar cal = pkcs7.getTimeStampDate();

        // If there is no timestamp, use the current date
        if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE == cal) {
            cal = Calendar.getInstance();
        }

        // Check if the certificate chain, presented in the PDF, can be verified against
        // the created key store.
        List<VerificationException> errors = CertificateVerification.verifyCertificates(certs, ks, cal);
        if (errors.size() == 0) {
            OUT_STREAM.println("Certificates verified against the KeyStore");
        } else {
            OUT_STREAM.println(errors);
        }

        // Find out if certificates were valid on the signing date, and if they are still valid today
        for (int i = 0; i < certs.length; i++) {
            X509Certificate cert = (X509Certificate) certs[i];
            OUT_STREAM.println("=== Certificate " + i + " ===");
            showCertificateInfo(cert, cal.getTime());
        }

        // Take the signing certificate
        X509Certificate signCert = (X509Certificate) certs[0];

        // Take the certificate of the issuer of that certificate (or null if it was self-signed).
        X509Certificate issuerCert = (certs.length > 1 ? (X509Certificate) certs[1] : null);

        OUT_STREAM.println("=== Checking validity of the document at the time of signing ===");
        checkRevocation(pkcs7, signCert, issuerCert, cal.getTime());

        OUT_STREAM.println("=== Checking validity of the document today ===");
        checkRevocation(pkcs7, signCert, issuerCert, new Date());

        return pkcs7;
    }

    public PdfPKCS7 getSignatureData(SignatureUtil signUtil, String name) throws GeneralSecurityException {
        PdfPKCS7 pkcs7 = signUtil.readSignatureData(name);

        OUT_STREAM.println("Signature covers whole document: " + signUtil.signatureCoversWholeDocument(name));
        OUT_STREAM.println("Document revision: " + signUtil.getRevision(name) + " of " + signUtil.getTotalRevisions());
        OUT_STREAM.println("Integrity check OK? " + pkcs7.verifySignatureIntegrityAndAuthenticity());

        return pkcs7;
    }

    public void showCertificateInfo(X509Certificate cert, Date signDate) {
        OUT_STREAM.println("Issuer: " + cert.getIssuerDN());
        OUT_STREAM.println("Subject: " + cert.getSubjectDN());
        SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
        date_format.setTimeZone(TimeZone.getTimeZone("Universal"));
        OUT_STREAM.println("Valid from: " + date_format.format(cert.getNotBefore()));
        OUT_STREAM.println("Valid to: " + date_format.format(cert.getNotAfter()));

        // Check if a certificate was valid on the signing date
        try {
            cert.checkValidity(signDate);
            OUT_STREAM.println("The certificate was valid at the time of signing.");
        } catch (CertificateExpiredException e) {
            OUT_STREAM.println("The certificate was expired at the time of signing.");
        } catch (CertificateNotYetValidException e) {
            OUT_STREAM.println("The certificate wasn't valid yet at the time of signing.");
        }

        // Check if a certificate is still valid now
        try {
            cert.checkValidity();
            OUT_STREAM.println("The certificate is still valid.");
        } catch (CertificateExpiredException e) {
            OUT_STREAM.println("The certificate has expired.");
        } catch (CertificateNotYetValidException e) {
            OUT_STREAM.println("The certificate isn't valid yet.");
        }
    }

    public static void checkRevocation(PdfPKCS7 pkcs7, X509Certificate signCert, X509Certificate issuerCert, Date date)
            throws GeneralSecurityException, IOException {
        List<IBasicOCSPResp> ocsps = new ArrayList<>();
        if (pkcs7.getOcsp() != null) {
            ocsps.add(new BasicOCSPRespBC(((BasicOCSPRespBC) pkcs7.getOcsp()).getBasicOCSPResp()));
        }

        // Check if the OCSP responses in the list were valid for the certificate on a specific date.
        OCSPVerifier ocspVerifier = new OCSPVerifier(null, ocsps);
        List<VerificationOK> verification = ocspVerifier.verify(signCert, issuerCert, date);

        // If that list is empty, we can't verify using OCSP, and we need to look for CRLs.
        if (verification.size() == 0) {
            List<X509CRL> crls = new ArrayList<X509CRL>();
            if (pkcs7.getCRLs() != null) {
                for (CRL crl : pkcs7.getCRLs()) {
                    crls.add((X509CRL) crl);
                }
            }

            // Check if the CRLs in the list were valid on a specific date.
            CRLVerifier crlVerifier = new CRLVerifier(null, crls);
            verification.addAll(crlVerifier.verify(signCert, issuerCert, date));
        }

        if (verification.size() == 0) {
            OUT_STREAM.println("The signing certificate couldn't be verified");
        } else {
            for (VerificationOK v : verification) {
                OUT_STREAM.println(v);
            }
        }
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        C5_03_CertificateValidation app = new C5_03_CertificateValidation();

        Logger ocspLogger = (Logger) LoggerFactory.getLogger(OCSPVerifier.class);
        Logger clrLogger = (Logger) LoggerFactory.getLogger(CRLVerifier.class);

        /* Add a custom appender to the specified logger.
         * Mind that if you have any added console appenders, then log messages in the console
         * could be shown multiple times.
         */
        setUpLogger(ocspLogger);
        setUpLogger(clrLogger);

        // Create your own root certificate store and add certificates
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(null, null);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        try (FileInputStream stream = new FileInputStream(ROOT)) {
            ks.setCertificateEntry("root", cf.generateCertificate(stream));
        }

        app.setKeyStore(ks);

        app.verifySignatures(EXAMPLE);

        // Detach the custom appender from the logger.
        resetLogger(ocspLogger);
        resetLogger(clrLogger);
    }

    private void setKeyStore(KeyStore ks) {
        this.ks = ks;
    }

    private static void setUpLogger(Logger logger) {
        appender = new CustomListAppender<ILoggingEvent>(OUT_STREAM);
        appender.setName("customAppender");
        appender.start();
        logger.addAppender(appender);
    }

    private static void resetLogger(Logger logger) {
        appender.stop();
        logger.detachAppender(appender);

    }

    // Custom log appender to write log messages to the specific print stream
    private static class CustomListAppender<E> extends AppenderBase<E> {
        private PrintStream stream;

        public CustomListAppender(PrintStream stream) {
            this.stream = stream;
        }

        @Override
        protected void append(E e) {
            ILoggingEvent event = (ILoggingEvent) e;
            stream.println(event.getLoggerName() + " " + event.getLevel() + " " + event.getMessage());
        }
    }
}

C#

C#
using System;
using System.Collections.Generic;
using System.IO;
using iText.Bouncycastle.Cert;
using iText.Bouncycastle.X509;
using iText.Commons;
using iText.Commons.Bouncycastle.Asn1.Ocsp;
using iText.Commons.Bouncycastle.Cert;
using iText.Kernel.Pdf;
using iText.Signatures;
using Microsoft.Extensions.Logging;
using Org.BouncyCastle.Security.Certificates;
using Org.BouncyCastle.X509;

namespace iText.Samples.Signatures.Chapter05
{
    public class C5_03_CertificateValidation
    {
        public static readonly string DEST = "signatures/chapter05/";

        public static readonly string ROOT = "../../../resources/encryption/rootRsa.cer";

        public static readonly string EXAMPLE = "../../../resources/pdfs/signedPAdES-LT.pdf";

        public const String EXPECTED_OUTPUT = "../../../resources/pdfs/signedPAdES-LT.pdf\n"
                                              + "===== Signature1 =====\n"
                                              + "Signature covers whole document: False\n"
                                              + "Document revision: 1 of 2\n"
                                              + "Integrity check OK? True\n"
                                              + "Certificates verified against the KeyStore\n"
                                              + "=== Certificate 0 ===\n"
                                              + "Issuer: C=BY,L=Minsk,O=iText,OU=test,CN=iTextTestRoot\n"
                                              + "Subject: C=BY,L=Minsk,O=iText,OU=test,CN=iTextTestRsaCert01\n"
                                              + "Valid from: 2017-04-07\n"
                                              + "Valid to: 2117-04-07\n"
                                              + "The certificate was valid at the time of signing.\n"
                                              + "The certificate is still valid.\n"
                                              + "=== Certificate 1 ===\n"
                                              + "Issuer: C=BY,L=Minsk,O=iText,OU=test,CN=iTextTestRoot\n"
                                              + "Subject: C=BY,L=Minsk,O=iText,OU=test,CN=iTextTestRoot\n"
                                              + "Valid from: 2017-04-07\n"
                                              + "Valid to: 2117-04-07\n"
                                              + "The certificate was valid at the time of signing.\n"
                                              + "The certificate is still valid.\n"
                                              + "=== Checking validity of the document at the time of signing ===\n"
                                              + "iText.Signatures.OCSPVerifier: Valid OCSPs found: 0\n"
                                              + "iText.Signatures.CRLVerifier: Valid CRLs found: 0\n"
                                              + "The signing certificate couldn't be verified\n"
                                              + "=== Checking validity of the document today ===\n"
                                              + "iText.Signatures.OCSPVerifier: Valid OCSPs found: 0\n"
                                              + "iText.Signatures.CRLVerifier: Valid CRLs found: 0\n"
                                              + "The signing certificate couldn't be verified"
                                              +"\n";

        public static TextWriter OUT_STREAM = Console.Out;
        private static ILoggerFactory defaultLoggerFactory;
        private List<IX509Certificate> ks;

        public void VerifySignatures(String path)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(path));
            SignatureUtil signUtil = new SignatureUtil(pdfDoc);
            IList<String> names = signUtil.GetSignatureNames();

            OUT_STREAM.WriteLine(path);
            foreach (String name in names)
            {
                OUT_STREAM.WriteLine("===== " + name + " =====");
                VerifySignature(signUtil, name);
            }
        }

        public PdfPKCS7 VerifySignature(SignatureUtil signUtil, String name)
        {
            PdfPKCS7 pkcs7 = GetSignatureData(signUtil, name);
            IX509Certificate[] certs = pkcs7.GetSignCertificateChain();
            
            // Timestamp is a secure source of signature creation time,
            // because it's based on Time Stamping Authority service.
            DateTime cal = pkcs7.GetTimeStampDate();
            
            
            // If there is no timestamp, use the current date
            if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE == cal) {
                cal = new DateTime();
            }

            // Check if the certificate chain, presented in the PDF, can be verified against
            // the created key store.
            IList<VerificationException> errors = CertificateVerification.VerifyCertificates(certs, ks, cal);
            if (errors.Count == 0)
            {
                OUT_STREAM.WriteLine("Certificates verified against the KeyStore");
            }
            else
            {
                OUT_STREAM.WriteLine(errors);
            }

            // Find out if certificates were valid on the signing date, and if they are still valid today
            for (int i = 0; i < certs.Length; i++)
            {
                IX509Certificate cert = certs[i];
                OUT_STREAM.WriteLine("=== Certificate " + i + " ===");
                ShowCertificateInfo(cert, cal.ToUniversalTime());
            }

            // Take the signing certificate
            IX509Certificate signCert = certs[0];

            // Take the certificate of the issuer of that certificate (or null if it was self-signed).
            IX509Certificate issuerCert = (certs.Length > 1 ? certs[1] : null);

            OUT_STREAM.WriteLine("=== Checking validity of the document at the time of signing ===");
            CheckRevocation(pkcs7, signCert, issuerCert, cal.ToUniversalTime());

            OUT_STREAM.WriteLine("=== Checking validity of the document today ===");
            CheckRevocation(pkcs7, signCert, issuerCert, new DateTime());

            return pkcs7;
        }

        public PdfPKCS7 GetSignatureData(SignatureUtil signUtil, String name)
        {
            PdfPKCS7 pkcs7 = signUtil.ReadSignatureData(name);

            OUT_STREAM.WriteLine("Signature covers whole document: " + signUtil.SignatureCoversWholeDocument(name));
            OUT_STREAM.WriteLine("Document revision: " + signUtil.GetRevision(name) + " of "
                                 + signUtil.GetTotalRevisions());
            OUT_STREAM.WriteLine("Integrity check OK? " + pkcs7.VerifySignatureIntegrityAndAuthenticity());
            return pkcs7;
        }

        public void ShowCertificateInfo(IX509Certificate cert, DateTime signDate)
        {
            OUT_STREAM.WriteLine("Issuer: " + ((X509CertificateBC)cert).GetCertificate().IssuerDN);
            OUT_STREAM.WriteLine("Subject: " + ((X509CertificateBC)cert).GetCertificate().SubjectDN);
            OUT_STREAM.WriteLine("Valid from: " + ((X509CertificateBC)cert).GetCertificate().NotBefore.ToUniversalTime().ToString("yyyy-MM-dd"));
            OUT_STREAM.WriteLine("Valid to: " + ((X509CertificateBC)cert).GetCertificate().NotAfter.ToUniversalTime().ToString("yyyy-MM-dd"));

            // Check if a certificate was valid on the signing date
            try
            {
                cert.CheckValidity(signDate);
                OUT_STREAM.WriteLine("The certificate was valid at the time of signing.");
            }
            catch (CertificateExpiredException)
            {
                OUT_STREAM.WriteLine("The certificate was expired at the time of signing.");
            }
            catch (CertificateNotYetValidException)
            {
                OUT_STREAM.WriteLine("The certificate wasn't valid yet at the time of signing.");
            }

            // Check if a certificate is still valid now
            try
            {
                ((X509CertificateBC)cert).GetCertificate().CheckValidity();
                OUT_STREAM.WriteLine("The certificate is still valid.");
            }
            catch (CertificateExpiredException)
            {
                OUT_STREAM.WriteLine("The certificate has expired.");
            }
            catch (CertificateNotYetValidException)
            {
                OUT_STREAM.WriteLine("The certificate isn't valid yet.");
            }
        }

        private static void CheckRevocation(PdfPKCS7 pkcs7, IX509Certificate signCert, IX509Certificate issuerCert,
            DateTime date)
        {
            IList<IBasicOcspResponse> ocsps = new List<IBasicOcspResponse>();
            if (pkcs7.GetOcsp() != null)
            {
                ocsps.Add(pkcs7.GetOcsp());
            }

            // Check if the OCSP responses in the list were valid for the certificate on a specific date.
            OCSPVerifier ocspVerifier = new OCSPVerifier(null, ocsps);
            IList<VerificationOK> verification = ocspVerifier.Verify(signCert, issuerCert, date);

            // If that list is empty, we can’t verify using OCSP, and we need to look for CRLs.
            if (verification.Count == 0)
            {
                IList<IX509Crl> crls = new List<IX509Crl>();
                if (pkcs7.GetCRLs() != null)
                {
                    foreach (IX509Crl crl in pkcs7.GetCRLs())
                    {
                        crls.Add((IX509Crl) crl);
                    }
                }

                // Check if the CRLs in the list were valid on a specific date.
                CRLVerifier crlVerifier = new CRLVerifier(null, crls);
                IList<VerificationOK> verificationOks = crlVerifier.Verify(signCert, issuerCert, date);
                foreach (VerificationOK verOK in verificationOks)
                {
                    verification.Add(verOK);
                }
            }

            if (verification.Count == 0)
            {
                OUT_STREAM.WriteLine("The signing certificate couldn't be verified");
            }
            else
            {
                foreach (VerificationOK v in verification)
                {
                    OUT_STREAM.WriteLine(v);
                }
            }
        }

        public static void Main(String[] args)
        {
            C5_03_CertificateValidation app = new C5_03_CertificateValidation();

            // Set up logger to show log messages from OCSPVerifier and CLRVerifier classes 
            SetUpLogger();

            // Create your own root certificate store and add certificates
            List<IX509Certificate> ks = new List<IX509Certificate>();
            var parser = new X509CertificateParser();
            IX509Certificate rootCert;
            using (FileStream stream = new FileStream(ROOT, FileMode.Open, FileAccess.Read))
            {
                rootCert = new X509CertificateBC(parser.ReadCertificate(stream));
            }

            ks.Add(rootCert);
            app.SetKeyStore(ks);

            app.VerifySignatures(EXAMPLE);

            // Reset logger to the default value
            ResetLogger();
        }

        private void SetKeyStore(List<IX509Certificate> ks)
        {
            this.ks = ks;
        }

        private static void SetUpLogger()
        {
            defaultLoggerFactory = ITextLogManager.GetLoggerFactory();
            ILoggerFactory customLoggerFactory = new LoggerFactory();
            customLoggerFactory.AddProvider(new CustomLoggerProvider(OUT_STREAM));
            ITextLogManager.SetLoggerFactory(customLoggerFactory);
        }

        private static void ResetLogger()
        {
            ITextLogManager.SetLoggerFactory(defaultLoggerFactory);
        }
        
        // Custom log provider to write log messages to the specific text writer
        private sealed class CustomLoggerProvider : ILoggerProvider
        {
            private readonly TextWriter writer;

            public CustomLoggerProvider(TextWriter writer)
            {
                this.writer = writer;
            }
            
            public ILogger CreateLogger(string categoryName) => new CustomLogger(categoryName, writer);

            public void Dispose()
            {
                // no need to release any resources
            }
        }
        
        private class CustomLogger : ILogger
        {
            private readonly string _name;
            private readonly TextWriter _writer;

            public CustomLogger(
                string name,
                TextWriter writer) =>
                (_name, _writer) = (name, writer);

            public IDisposable BeginScope<TState>(TState state)
            {
                // no need to use scope logic
                throw new NotImplementedException();
            }

            public bool IsEnabled(LogLevel logLevel)
            {
                // we allow all log levels in this simple example
                return true;
            }

            public void Log<TState>(
                LogLevel logLevel,
                EventId eventId,
                TState state,
                Exception exception,
                Func<TState, Exception, string> formatter)
            {
                _writer.WriteLine(_name + ": " + formatter(state, exception));
            }
        }
    }
}

JavaScript errors detected

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

If this problem persists, please contact our support.