Skip to main content
Skip table of contents

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.