Skip to main content
Skip table of contents

Breaking changes for iText 8

Sign module

Also see Bouncy-castle related changelog.

Breaking change

IExternalSignature interface:

  • getHashAlgorithm is renamed to getDigestAlgorithmName

  • getEncryptionAlgorithm is renamed to getSignatureAlgorithmName

PrivateKeySignature class implements IExternalSignature. So the changes are similar:

  • getHashAlgorithm is renamed to getDigestAlgorithmName

  • getEncryptionAlgorithm is renamed to getSignatureAlgorithmName

  • getSignatureMechanism became private (from public)

PdfPKCS7 class:

  • getHashAlgorithm is renamed to getDigestAlgorithmName

  • getDigestEncryptionAlgorithmOid is renamed to getSignatureMechanismOid

  • getDigestAlgorithm is renamed to getSignatureMechanismName

  • getEncryptionAlgorithm is renamed to getSignatureAlgorithmName

  • setExternalDigest is renamed to setExternalSignatureValue

EncryptionAlgorithms class is renamed to SignatureMechanisms

Commons module

Breaking change

Upgrade path

ZipFileReader class:

  • IOException is added as a thrown exception to getFileNames() method

Update usages in tests only.

DateTimeUtil class

  • method getCurrentTimeZoneOffset() is removed

Replaced by DateTimeUtil#getCurrentTimeZoneOffset(Date)

IO module

Breaking change

Upgrade path

IoLogMessageConstant class, the following unused constants are removed:

  • CANNOT_ADD_KID_HINT_WHICH_IS_ALREADY_ADDED_TO_ANOTHER_PARENT 

  • DOCUMENT_SERIALIZATION_EXCEPTION_RAISED

  • ELEMENT_DOES_NOT_FIT_AREA

  • INPUT_STREAM_CONTENT_IS_LOST_ON_PDFSTREAM_SERIALIZATION

  • N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY

  • TAGGING_HINT_NOT_FINISHED_BEFORE_CLOSE

  • TAG_STRUCTURE_CONTEXT_WILL_BE_REINITIALIZED_ON_SERIALIZATION

  • UNABLE_TO_INTERRUPT_THREAD 

  • XFDF_OUTPUT_STREAM_CORRUPTED


UrlUtil class:

Method getFinalURL(URL initialUrl) is removed

Use UrlUtil.getInputStreamOfFinalConnection(URL) instead.

CMapCidByte class is renamed to CMapCidToCodepoint

FontCache class:

  • getCid2Byte method is renamed to getCidToCodepointCmap

CMapEncoding class:

  • containsCodeInCodeSpaceRange method is removed (was moved to PdfType0Font as a private method).

Update usages.

Styled-xml-parser module

Breaking change

Upgrade path

DataUtil class:

  • Method mimeBoundary() is removed

Update usages in tests only.

Forms module

See Forms related changelog.

Kernel module

Breaking change

Upgrade path

PdfNameTree is extended from GenericNameTree:

  • Returned type from getNames() method is changed from Map<String, PdfObject> to Map<PdfString, PdfObject>

Update usages.

PdfDestination, PdfExplicitDestination, PdfExplicitRemoteGoToDestination, PdfNamedDestination, PdfStringDestination and PdfStructureDestination classes:

  • in getDestinationPage parameter Map<String, PdfObject> is changed to IPdfNameTreeAccess.

Update usages.

Switch to new IPdfFunction hierarchy instead of old PdfFunction:

  • Constructors for DeviceN and Separation classes which take deprecated PdfFunction were removed.

  • Public methods of PdfShading were switched to using IPdfFunction instead of deprecated PdfFunction.

Update usages.

Two constants are removed from KernelExceptionMessageConstant:

  • UNEXPECTED_CLOSE_BRACKET

  • UNEXPECTED_GT_GT


Method getUniMapFromOrdering(String ordering) is removed from PdfType0Font.

Use method getUniMapFromOrdering(String, boolean) instead

Method storeLinkAnnotation is removed from PdfDocument.

Internal usage, use method storeDestinationToReaddress

Class PdfFunction is removed.

Use classes PdfType0Function, PdfType2Function, PdfType3Function

or PdfType4Function instead.   

SVG module

Breaking change

SvgExceptionMessageConstant class, the following constants are removed:

  • PATH_OBJECT_MUST_HAVE_D_ATTRIBUTE

  • RENDERER_WITHOUT_OBJECT_BOUNDING_BOX


Forms module changes

Overview

In the scope of the 8.0.0 release we've introduced several major breaking changes in the forms module of the itextcore repository.

List of breaking changes:

  • Form fields with the same fully qualified names are now merged with each other.

    • If these fields have a different field type, value or default value, a log will be displayed (in the reading mode or when reading the document) or an exception will be thrown (in cases when the user tries to add a field with the same name as an already existing one, but different /FT, /V or /DV values). Merge occurs when an acroform is created, when children are added to a field, when field is renamed, or when fields are added to an acroform. 
      PdfAcroForm.addField(PdfFormField, PdfPage, boolean) can be used to not throw an exception while adding a new field.

    • setValue method sets the value not only to the field setValue is called on, but also to its siblings (children of the parent field) if they have the same fully qualified name. Such fields may present when it was not possible to merge them, or, for example, during acroform reading.

    • If there are 2 fields in the hierarchy of fields – a parent without /T entry and a child, and the child has all the values in its dictionary (except for /Parent and /Kids) that match the parent values, and child /Kids contain only annotations (no form fields), then this child will be merged with the parent, that is, the /Kids of the child will become the /Kids of the parent. This makes the document structure cleaner (field annotations become pure widgets). Parent should not have /T entry because we only want to perform such a merge if the field doesn't contain any name (even an empty one).
      For radio groups, all of its child form fields are merged with it, since radio group should contain only annotation children according to the specification. This means that we force radio buttons to be pure widgets in order to match the PDF specification.

    • For fields with multiple widgets, all annotations are added to the page (previously only fields with one widget were supported).

  • PdfFormField.setValue doesn't set the value to the child form fields any longer.

  • PdfAcroForm.replaceFieldfields now get replaced in their parents, where previously they just would have been added to the main form dictionary.

  • Fields (including merged fields) that do not have /T key are considered fields named "" (empty string). 

    Changed PdfFormField logic to be able to add fields without partial name. In general we leave the field without changes and treat it's name as an empty string. This name is handled as any other name, since an empty string is still a string (e.g. fields merging, search, remove, etc...). Full name for field's children looks like rootFieldName.parentFieldName.childName In this particular case parentFieldName will be an empty string. This behavior violates the PDF 2.0 specification, but it is valid for PDF 1.7.

  • Moved radio button, push button, checkbox, text field drawing logic from forms to renderers.

    • This led to some changes in the fields appearance, and now flattened and interactive fields are drawn in almost the same way.

    • Also fixed a bug related to fields stream data: it was written to the content stream of the page before, but now it is in the field normal appearance which is used for drawing the annotation.

    • Creating fields using model element became much more convenient. Currently we have two main ways to create form field in the acroform structure:

      1. First one is the old one: through the usage of PdfAcroForm class.

      2. Second one is much less complicated and easy for users. One needs to simply create a layout element related to form fields and add it to the Document object like we usually do for other layout elements (such as Paragraph, Table, Div, etc...). After that, the form field will be automatically placed on the page and related elements will be added to the acroform if iterative mode is enabled. This is not yet supported for choice form fields.

    • Text form field drawing logic was moved to TextAreaRenderer and InputFieldRenderer.

      • Text drawing was moved to the related layout elements.

      • Text approximation is improved.

      • Border drawing bug with border being 2 times smaller was fixed.

      • Text no longer overlaps the border.

    • Some new classes were added for checkboxes drawing:

      /form/renderer/checkboximpl/HtmlCheckBoxRenderingStrategy.java

      /form/renderer/checkboximpl/ICheckBoxRenderingStrategy.java

      /form/renderer/checkboximpl/PdfACheckBoxRenderingStrategy.java

      /form/renderer/checkboximpl/PdfCheckBoxRenderingStrategy.java

  • Model element can be passed to PdfFormAnnotation by using public PdfFormAnnotation setFormFieldElement(IFormField element). Note that annotation properties will take precedence, so such properties cannot be overridden by using this method (e.g. background, text color, etc.), but it can be useful to take into account when drawing those properties that the annotation does not have (e.g. paddings). Also note that the model element won't be used for annotations for choice form fields.

  • Each model element is responsible for one annotation. We can add them to the document using Document.add method. Elements with the same id will be responsible for the annotations of the field with the name equal to id. Note that fields with the same fully qualified field name shall have the same field type, value, and default value to merge it without problems.
    Re-adding the same model element two or more times can lead to an undefined behavior since model element properties is changed in PdfFormAnnotation.

API changes:

Breaking change

Upgrade path

Created builder classes for every different PdfFormField implementation instead of static creator methods in PdfFormField class:

com.itextpdf.forms.fields.CheckBoxFormFieldBuilder.java

com.itextpdf.forms.fields.ChoiceFormFieldBuilder.java

com.itextpdf.forms.fields.PushButtonFormFieldBuilder.java

com.itextpdf.forms.fields.RadioFormFieldBuilder.java

com.itextpdf.forms.fields.SignatureFormFieldBuilder.java

com.itextpdf.forms.fields.TextFormFieldBuilder.java

com.itextpdf.forms.fields.FormFieldBuilder.java

com.itextpdf.forms.fields.NonTerminalFormFieldBuilder.java

com.itextpdf.forms.fields.TerminalFormFieldBuilder.java

Use builders instead of old creator methods and set appropriate properties, e.g. instead of

JAVA
PdfFormField.createText(pdfDoc, new Rectangle(100, 600, 200, 30), 
"Name", "Enter your name")

use

JAVA
PdfTextFormField textField = new TextFormFieldBuilder(pdfDoc, "Name")
.setWidgetRectangle(new Rectangle(100, 600, 200, 30))
.createText();
textField.setValue("Enter your name");

PdfAcroForm started to store only its direct children instead of all descending form fields (and every form field stores its kids). This affected every operation related to fields management (add, remove, get), so
public Map<String, PdfFormField> getFormFields() usage should be replaced either by
public Map<String, PdfFormField> getRootFormFields() or getAllFormFields() that were added to PdfAcroForm, and some convenient methods related to child fields were added in PdfFormField.

Use getRootFormFields() for getting all root fields (i.e. direct children of Acroform dictionary) or getAllFormFields() for getting all descending fields (including the children of the children).

PdfFormField class was split onto PdfFormField and PdfFormAnnotation. Methods related to widget annotations used from form fields were moved to PdfFormAnnotation:

setPage, setBackgroundColor, setRotation, setAction, setVisibility, setBorderWidth, setBorderColor, setBorderStyle, setAppearance.

A few convenience getters were added into PdfFormField:

getChildFormAnnotations, getFirstFormAnnotation. They can be used to reach child annotations.

First use getFirstFormAnnotation or getChildFormAnnotations of PdfFormField and then call the corresponding method.

Generating appearance was moved from PdfFormField to PdfFormAnnotation class. Some of them were also renamed:

  • drawRadioAppearance to drawRadioButtonAndSaveAppearance

  • drawTextAppearance, drawMultiLineTextAppearance to drawTextFormFieldAndSaveAppearance

  • drawPushButtonAppearance to drawPushButtonFieldAndSaveAppearance

  • drawCheckAppearance, drawPdfA2CheckAppearance to drawCheckBoxAndSaveAppearance

If you used to override some drawing methods in PdfFormField, from now on you have to subclass PdfFormAnnotation and override the corresponding drawing methods.

For example, PdfFormAnnotation.drawRadioButtonAndSaveAppearance has to be overridden instead of PdfFormField.drawRadioAppearance.

Model element classes and corresponding renderers were moved from html2pdf to forms module:

/form/element/AbstractSelectField.java

/form/element/Button.java (InputButton is merged with Button)

/form/element/CheckBox.java

/form/element/ComboBoxField.java

/form/element/FormField.java

/form/element/IFormField.java

/form/element/InputField.java

/form/element/IPlaceholderable.java

/form/element/ListBoxField.java

/form/element/Radio.java

/form/element/TextArea.java

/form/renderer/AbstractFormFieldRenderer.java

/form/renderer/AbstractOneLineTextFieldRenderer.java

/form/renderer/AbstractSelectFieldRenderer.java

/form/renderer/AbstractTextFieldRenderer.java

/form/renderer/ButtonRenderer.java (InputButtonRenderer is merged with ButtonRenderer)

/form/renderer/CheckBoxRenderer.java

/form/renderer/InputFieldRenderer.java

/form/renderer/RadioRenderer.java

/form/renderer/SelectFieldComboBoxRenderer.java

/form/renderer/SelectFieldListBoxRenderer.java

/form/renderer/TextAreaRenderer.java

/form/FormProperty.java (some properties were moved from Html2PdfProperty)

Changed radio buttons creation logic to make them pure widgets instead of form fields: radio buttons changed from a PdfFormField to a PdfFormAnnotation and should be explicitly added to the desired radio button group.

For radio buttons use PdfFormAnnotation instead of PdfFormField and explicitly add it to the group by using PdfButtonFormField.addKid

Example of usage:

JAVA
PdfButtonFormField group = new RadioFormFieldBuilder(doc, formFieldName)
                 .createRadioGroup();
PdfFormAnnotation radio = builder.createRadioButton("1", rect)
                .setVisibility(PdfFormAnnotation.VISIBLE);
group.addKid(radio);

More user friendly enums are introduced/used for check box types and fields justification.

  • PdfFormField flags related to check box creation: com.itextpdf.forms.fields.properties.CheckBoxType is added,

    • public PdfFormField setCheckType(int checkType) changed to public PdfFormField setCheckType(CheckBoxType checkType)

  • TextAlignment is used for justification:

    • PdfFormField#setJustification(int) is changed to PdfFormField#setJustification(com.itextpdf.layout.properties.TextAlignment),

    • public Integer getJustification() is changed to public TextAlignment getJustification()

Use CheckBoxType enum values instead of integer values while setting check type. Also use TextAlignment for setting/getting justification.

Moved radio button, push button, checkbox, text field drawing logic from forms to renderers (drawButton, drawCheckBox, drawPdfACheckBox, drawRadioBorder and drawRadioField are deleted since those methods aren't needed anymore).

  • drawRadioAppearance is replaced by drawRadioButtonAndSaveAppearance

  • drawTextAppearance, drawMultiLineTextAppearance are replaced by drawTextFormFieldAndSaveAppearance

  • drawPushButtonAppearance is replaced by drawPushButtonFieldAndSaveAppearance

  • drawCheckAppearance, drawPdfA2CheckAppearance are replaced by drawCheckBoxAndSaveAppearance

  • drawChoiceAppearance moved

InputButton was merged with Button, also InputButtonRenderer was merged with ButtonRenderer which extends AbstractTextFieldRenderer instead of BlockRenderer. We can create one-line push button by using public Button setSingleLineValue(String value) to set caption for Button element.
Also FormProperty.FORM_FIELD_VALUE is not supported for Button element.
Font color issue is fixed: color set to an annotation with setColor method is now applied to button fields.
Appearance of buttons with multiple elements inside changed to be similar to how it is displayed when opening the HTML document: all children are centered and wrap to a new line if necessary.
After adding a field inside a button this field will be flattened.

Use Button instead of InputButton and setSingleLineValue method instead of setting FormProperty.FORM_FIELD_VALUE. For multiline value use setValue or create paragraph and use add(IBlockElement)

Drawing logic related to comb property and choice fields was moved to the new TextAndChoiceLegacyDrawer class.


exceptions/FormsExceptionMessageConstant.java

  • WRONG_FORM_FIELD_ADD_ANNOTATION_TO_THE_FIELD is deleted,

  • N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY is moved to FormsLogMessageConstants




Bouncy Castle changes

Overview

In the scope of the 8.0.0 release, we've introduced several major breaking changes in the way we handle bouncy-castle dependencies. Now we no longer use org.bouncycastle dependencies directly in our kernel and sign modules. Instead, all the necessary bouncy-castle related classes are grouped into two new modules: bouncy-castle-adapter and bouncy-castle-fips-adapter.

One of these modules is required to be in a classpath for the correct usage of cryptographic and signatures-related logic of our kernel and sign modules. However, by default they are not added as a dependency in order to provide the ability to choose one of them from the customer's side.

It is important not to add them both as a dependency since they are not compatible

Basically, this means that in order to use any other iText product (except several products which will be mentioned later) together with cryptographic or signatures-related logic either the bouncy-castle-adapter or bouncy-castle-fips-adapter module shall be added as a dependency. Otherwise, a special log message will be generated, such as the following:

TEXT
Either com.itextpdf:bouncy-castle-adapter or com.itextpdf:bouncy-castle-fips-adapter dependency must be added in order to use BouncyCastleFactoryCreator

Android version limitations

Android artifacts directly depend on vanilla BouncyCastle, and don't support switching to BouncyCastle FIPS.

The whole idea behind adding the possibility to depend on BouncyCastle-FIPS in iText Core is that this build of Bouncy-Castle is FIPS-certified, i.e. it adheres to the FIPS standard as confirmed by a certification process.

Status of known vulnerability CVE-2022-45146 for FIPS Java API before 1.0.2.4

The whole idea behind adding the possibility to depend on BouncyCastle-FIPS in iText Core is that this build of Bouncy-Castle is FIPS-certified, i.e. it adheres to the FIPS standard as confirmed by certification process. 

So, there are two reasons why iText Core keeps 1.0.2.3 dependency as the default one:
1) The only available version with the fix, 1.0.2.4, is not FIPS-certified (see https://www.bouncycastle.org/latest_releases.html#1.0.2.4-NONCERT)
2) BC-FIPS 1.0.2.3 is specifically certified against JRE 1.7, JRE 1.8, and JRE 1.11 (see https://www.bouncycastle.org/download/bouncy-castle-java-fips/roadmap/).

So, the expectation is that a user would want to opt-in to BC-FIPS dependency only with BC-FIPS 1.0.2.3 version and only for Java 8 or Java 11, while CVE-2022-45146 is only relevant to Java 13+.

It's also possible to switch to 1.0.2.4 by explicitly specifying this version in the Maven pom file.

The inside of bouncy-castle adapters

Java

com.itextpdf:bouncy-castle-adapter  Maven module encapsulates the bouncy-castle related classes for these two Maven dependencies:

  • org.bouncycastle:bcpkix-jdk15on

  • org.bouncycastle:bcprov-jdk15on

com.itextpdf:bouncy-castle-fips-adapter Maven module encapsulates the bouncy-castle related classes for these two Maven dependencies:

  • org.bouncycastle:bcpkix-fips

  • org.bouncycastle:bc-fips

.NET

itext7.bouncy-castle-adapter NuGet package encapsulates the bouncy-castle related classes for this NuGet dependency:

  • BouncyCastle.Cryptography

The itext.bouncy-castle-adapter previously relied upon the Portable.BouncyCastle dependency. However, as of the release of iText version 8.0.2, we transitioned to use the newer BouncyCastle.Cryptography package officially maintained by the Legion of the Bouncy Castle Inc.

itext7.bouncy-castle-fips-adapter NuGet package encapsulates the bouncy-castle related classes for these two assemblies (dlls taken from https://www.bouncycastle.org/download/bouncy-castle-c-fips/):

  • bc-fips-1.0.1.1

  • bcpkix-fips-1.0.1

Since those two dll files are not signed, we can't use them with .NET Framework and therefore the only supported target framework for bouncy-castle-fips-adapter project is netstandard2.0.

Ways to specify adapter

The idea of using adapters relies on the fact that only one adapter will be used in order to generate bouncy-castle related wrappers. The choice of adapter happens in the separate bouncy-castle-connectormodule. If for some reason both bouncy-castle-adapter and bouncy-castle-fips-adapter dependencies are added, there are still ways to specify which one need to be used.

First of all, the connector module searches for the special system or environment variable called ITEXT_BOUNCY_CASTLE_FACTORY_NAME. There are three possible values here:

  1. "bouncy-castle" - forces connector to first try to use bouncy-castle-adapter  module

  2. "bouncy-castle-fips" - forces connector to first try to use bouncy-castle-fips-adapter  module

  3. anything else - ignored

However, the related dependency should still be added in order to successfully use the related module.

Bouncy-castle-fips-adapter module operating modes

Bouncy-castle-fips-adapter module can be operated in two modes:

  • General mode

  • Approved mode

Note that only approved mode provides full FIPS compliance

General mode is enabled by default. There are several ways to enable approved mode.

Java:

  • Call CryptoServicesRegistrar#setApprovedOnlyMode(true) method

  • Pass "org.bouncycastle.fips.approved_only=true" VM parameter to your build configuration

.NET:

  • Call CryptoServicesRegistrar#SetApprovedOnlyMode(true) method

  • Pass environment or system variable ITEXT_DOTNET_BOUNCY_CASTLE_FIPS_MODE with "approved_mode" value

Ones approved mode is enabled, you can't go back to the general mode. Also this operating mode is thread local, i.e. it needs to be explicitly set per each thread.

Several algorithms are not available in the approved mode (such as MD5 for example). You will receive a corresponding log message if an algorithm is not FIPS compliant and therefore cannot be used in approved mode.

API usage

In the scope of these changes several public API methods definitions also changed. Right now we use special interfaces instead of org.bouncycastle classes in our API as a parameter or return values. In cases when you need to work with such interfaces to either create them from actual org.bouncycastle values or retrieve actual values, you should access classes from either bouncy-castle-adapter or bouncy-castle-fips-adapter directly, and either call the constructor to create an instance and pass it as a parameter, or call the corresponding getter method to retrieve the actual value. Let's take a more precise look at one of the examples.

Let's say you need to create IX509Certificate interface in order to pass it as a parameter to PdfSigner#SignDetached method, and assuming you already have X509Certificate object. Here there are two cases:

  • If you are using the bouncy-castle-adapter dependency, then you should create X509CertificateBC class (i.e. a class with the same name with BC postfix) passing your original X509Certificate as a parameter to the constructor, and then use this created wrapper as a parameter for PdfSigner#SignDetached method.

  • If you are using the bouncy-castle-fips-adapter dependency, then you should create X509CertificateBCFips class passing your actual X509Certificate as a parameter, and then use this created wrapper as a parameter for PdfSigner#SignDetached method.

Correspondingly, if you for example need to retrieve an actual X509Certificate object from either X509CertificateBC or X509CertificateBCFips, you should call GetCertificate method.

This workflow is valid for each wrapper from bouncy-castle-adapter and bouncy-castle-fips-adapter modules, with the respective names.

Let's take a look at the code.

.NET

before:

CODE
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;
}

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(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);

after:

CODE
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);

Java

before:

CODE
if (TimestampConstants.UNDEFINED_TIMESTAMP_DATE != pkcs7.getTimeStampDate()) {
     System.out.println("TimeStamp: " + date_format.format(pkcs7.getTimeStampDate().getTime()));
     TSTInfo ts = pkcs7.getTimeStampToken();
     System.out.println("TimeStamp service: " + ts.getTimeStampInfo().getTsa());
     System.out.println("Timestamp verified? " + pkcs7.verifyTimestampImprint());
}

after:

CODE
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());
}

JavaScript errors detected

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

If this problem persists, please contact our support.