Skip to content

Questions & Answers

Risto Seene edited this page Mar 12, 2024 · 103 revisions

Questions & Answers

Discontinuation of TimeMark signature creation

In the second half of 2023, the support for creating TimeMark-based signatures was phased out:

  • Since November 1, 2023, the paid OCSP service provided by SK ID Solutions AS does not support the creation of TimeMark signatures.
  • Since August 8, 2023, the demo OCSP service provided by SK ID Solutions AS does not support the creation of TimeMark signatures.
  • Since DigiDoc4j version 5.2.0, the support for creating TimeMark-based signatures was discontinued.

This does not affect the validation of existing TimeMark signatures or the validation of existing containers containing TimeMark signatures.

"Not supported: Can't create LT_TM signatures" error when trying to create LT_TM profile signatures.

Since DigiDoc4j version 5.2.0, the support for creating TimeMark-based signatures was discontinued! Read more from here.

"Cannot add BDoc specific (LT_TM) signature to ASiCE container" error on adding LT_TM profile signature to container.

TimeMark-based signatures were only allowed for Estonian specific BDOC containers, the creation of which has been discontinued.

Signer certificate for the EU List of eIDAS Trusted Lists (LOTL) was changed on 25.03.2021. This results in failure to sign or validate signatures with DD4J version 4.1.0.

It is needed to upgrade to Digidoc4j version 4.1.1 or specify the updated keystore location as shown here. You can get the up to date keystore with needed certificates in here.

"OCSP Responder does not meet TM requirements" error on validation of BDOC containers (since version 3.0.0)

TimeMark-based signatures are only allowed for specific OCSP responders with TimeMark compatibility. This list is maintained by DigiDoc4j library by default, however, this list might be incomplete in old versions of DigiDoc4j. Therefor, there may be need to update the accepted list of OCSP responders manually. To allow new TimeMark-capable OCSP responders, digidoc4j.yaml must be used and updated with ALLOWED_OCSP_RESPONDERS_FOR_TM parameter. All allowed OCSP responders must be listed.

NB! new TEST of SK OCSP RESPONDER 2020 was introduced 16.11.2020 for http://demo.sk.ee/ocsp This means that digidoc4j-test.yaml must be updated and used for validating BDOC containers. Following parameters with values must be added: ALLOWED_OCSP_RESPONDERS_FOR_TM: TEST of SK OCSP RESPONDER 2011, TEST of EID-SK 2016 OCSP RESPONDER 2018, TEST of SK OCSP RESPONDER 2020

Unable to load the LOTL: content is empty error

EU is in process of changing the location of member states trust providers List of Trusted Lists (LOTL). This list is essential for creating and validating signatures with Digidoc4j. The reason for this error may be that your current Digidoc4j integration uses the old location (https://ec.europa.eu/information_society/policy/esignature/trusted-list/tl-mp.xml) for the before mentioned LOTL and it is not available anymore. To solve the problem Digidoc4j needs to be pointed to the correct location: https://ec.europa.eu/tools/lotl/eu-lotl.xml.

There are different options to set the new location:

  • Set the new location through digidoc4j.yaml file to override the LOTL location. The general instructions can be found here:
    • before version 5.0.0: TSL_LOCATION: "https://ec.europa.eu/tools/lotl/eu-lotl.xml"
    • since version 5.0.0: LOTL_LOCATION: "https://ec.europa.eu/tools/lotl/eu-lotl.xml"
  • Set the new location programmatically via Configuration object. The general instructions can be found here:
    • before version 5.0.0: configuration.setTslLocation("https://ec.europa.eu/tools/lotl/eu-lotl.xml");
    • since version 5.0.0: configuration.setLotlLocation("https://ec.europa.eu/tools/lotl/eu-lotl.xml");

TSL loading fails with TslRefreshException, TslDownloadException, TslParsingException or TslValidationException

In DigiDoc4J version 5.0.0 a configurable mechanism for TSL refresh callbacks was added. In case no custom callback is configured and DigiDoc4J uses its default implementation of the callback, any of the following exceptions might be thrown either when triggering a TSL refresh manually, or when creating or validating signatures (which might trigger a TSL refresh automatically if the internal state of the TSL has expired):

  • TslRefreshException - a generic error, encountered during loading or refreshing the TSL, or an aggregating exception that aggregates a collection of other exceptions that have occurred during loading or refreshing the TSL.

An inconclusive list of possible error messages and their meanings:

  • Loading or refreshing the LOTL has failed with:
    • Failed to download LoTL: https://... or Failed to download <EU> LoTL: https://... - LOTL has failed to download successfully. See the cause of the exception for more information.
    • Failed to parse LoTL: https://... or Failed to parse <EU> LoTL: https://... - LOTL has failed to parse successfully. See the cause of the exception for more information.
    • Failed to validate LoTL: https://... or Failed to validate <EU> LoTL: https://... - LOTL has failed to validate successfully. See the cause of the exception for more information.
  • Failed to load any trusted lists for LoTL: https://... or Failed to load any trusted lists for <EU> LoTL: https://... - no national Trusted Lists have been successfully loaded or refreshed for the specified LOTL. See the cause of the exception and/or suppressed exceptions for more information.
  • Failed to load trusted lists for required territories: ... - national Trusted Lists for any of the territories that have been configured as required have failed to load or refresh successfully. See the cause of the exception and/or suppressed exceptions for more information. More information about configuring the list of required territories can be found here.

In case the default TSL refresh callback is not suitable for specific needs and requirements, a custom callback can be implemented and specified. More information about the TSL refresh callbacks can be found here.

TSL loading fails because of TLS certificate trust issues

Any of the following could indicate the failure to load LOTL or any of the national Trusted Lists in case the server hosting the requested resource over a secure connection is not trusted by DigiDoc4j:

  • ERROR message in log, containing Unable to process GET call for url and/or Reason : [PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target].
  • WARN message in log, containing Failed to download LoTL: https://..., Failed to download <EU> LoTL: https://..., Failed to download TL: https://... or Failed to download <...> TL: https://..., and the previously listed messages or parts of them.
  • TslDownloadException, containing the previously listed messages or parts of them, is thrown either directly, or as the cause of or as a suppressed exception in a TslRefreshException.
  • Unable to load parts of TSL may cause:
    • signature validation failures with errors like Unable to build a certificate chain up to a trusted list! and/or The certificate chain for signature is not trusted, it does not contain a trust anchor.;
    • signature creation failures because of not being able to perform OCSP requests.

The lack of trust could be caused by the following problems:

  • If you are using DigiDoc4j 5.X.X and you have not configured a custom TLS truststore, then the TLS certificate chain of the problematic LOTL or Trusted List may not be trusted by the default Java TLS truststore.
  • If you are using a custom TLS truststore or DigiDoc4j 4.X.X, then the TLS certificate chain of the problematic LOTL or Trusted List may not be trusted by the custom TLS truststore (or the TLS truststore provided by DigiDoc4j 4.X.X).
  • The server that hosts the problematic LOTL or Trusted List may present an incomplete or invalid certificate chain during TLS handshake, making it impossible to build the trust chain from the presented certificate to the certificate that is trusted in the TLS truststore used by DigiDoc4j.

Known issues:

  • Starting from around January 22, 2024, the server hosting Lithuanian Trusted List (https://elektroninisparasas.lt/LT-TSL.xml) presents an invalid certificate chain which causes the TLS handshake to fail when using the default Java TLS truststore. In order to be able to load the Lithuanian Trusted List, a custom TLS truststore, containing the Lithuanian TLS certificate or its immediate CA, must be used.

Integrating with Web browsers

See a working example: DigiDoc4j with hwcrypto.js example demo Web application

It is possible to use DigiDoc4j when signing documents using a Web Browser (Chrome, Firefox, IE, Safari). A JavaScript framework called hwcrypto.js can be used to integrate digital signing functionality on a Web page. Take a look at hwcrypto.js API description. Note that the old idCard.js cannot be used anymore by Chrome and the new hwcrypto.js is asynchronous demanding a dynamic page with Ajax. Note also that hwcrypto.js works properly only over HTTPS.

In the external signing example, the getSignerCertSomewhere method should return the certificate fetched by hwcrypto.js getCertificate call. This returns a certificate object. This is a hex string that can be turned into a byte array by using DatatypeConverter.parseHexBinary(certificateInHex); for example. You could then rename this method to getSignerCertFromBrowser instead.

In the same external signing example, the signDataSomewhereRemotely method should calculate digest of the signable data using the provided hash algorithm and call the hwcrypto.js sign method that returns a signature object (in hex) that must be turned into a byte array. This can also be done by using DatatypeConverter.parseHexBinary(signatureInHex); for example. You could then rename the signDataSomewhereRemotely method to signDataInBrowser instead.

NB! When using hwcrypto.js for signing, special care must be taken to prevent the user from being able to re-initiate the signing process before the previous invocation of the process has been completed - for example, by clicking the "sign" button repeatedly. This may result in failure of signature creation as new dataToSign instance is generated for each click and they get out of sync between hwcrypto and DigiDoc4j, possibly resulting in the following log message:

WARN org.digidoc4j.impl.asic.xades.XadesSigningDssFacade - Signing document in DSS eu.europa.esig.dss.DSSException: Cryptographic signature verification has failedfailed:Cryptographic signature verification has failed / Certificate #1: Signature verification failed

NB: DigiDoc4j hwcrypto demo is outdated and is pending update.

Take a look at an example of signing with JavaScript.

If OCSP request has failed

If you get an ERROR message in log, containing Signature does not contain OCSP response, or an OCSPRequestFailedException (with message containing OCSP request failed) is thrown, then there could be any of the following reasons.

If you are using DigiDoc4j in production mode (configuration is in PROD mode) and the default OCSP service http://ocsp.sk.ee/ (AIA OCSP is not used), then either:

  • You must have an IP based access to the OCSP service (http://ocsp.sk.ee/)
  • Or your OCSP requests must be signed by an OCSP Access Certificate (juurdepääsutõend)
    • The Configuration class has the following methods for configuring OCSP: setOCSPAccessCertificateFileName, setOCSPAccessCertificatePassword, setSignOCSPRequests and setOcspSource.
    • Via digidoc4j.yaml, OCSP can be configured using the following parameters: DIGIDOC_PKCS12_CONTAINER, DIGIDOC_PKCS12_PASSWD and SIGN_OCSP_REQUESTS.

If you are using DigiDoc4j in test mode (configuration is in TEST mode), then you must take the following into consideration:

  • It is not possible to sign with production ID-cards/Mobile-ID/Smart-ID. Only test ID-cards, demo Mobile-ID numbers or demo Smart-ID accounts can be used in test mode. (since version 3.1.0)
  • You have to upload your TEST ID-card signing certificate to the test OCSP service at https://demo.sk.ee/upload_cert/. This would allow you to sign with your test ID-card and the OCSP service would return a valid response.
  • The test TSL does not contain production certificates, so it is not possible to create a valid signature with production ID-card/Mobile-ID/Smart-ID in TEST mode.

If none of the above applies but the problem still persists, then ensure that the Trusted List containing the trust service which has issued the signer's certificate has been loaded properly.

NB: If, for example, you are creating signatures using a signer's certificate issued by an Estonian trust service, or you are requesting timestamps from an Estonian timestamping service, then ensure that loading Estonian Trusted List is enabled and it loads properly!

How to test with ID card?

  • If you want to test with your production ID card then you have to test in the production (PROD) mode.
  • If you want to test in the TEST mode, then you have to use test ID cards.
  • It is NOT possible to test in the TEST mode using production ID cards (since version 3.1.0).
  • The test TSL does not contain production certificates so it is not possible to create a signature with production ID card in the test mode.
  • Here's an example of accessing smart card on your device to sign with a physical ID card.

Why is the library that slow?

DigiDoc4j is slow only in the first run, when it downloads the EU TSL (EU Trusted Lists of Certificates). TSL is refreshed once a day (by default) and it takes time to download (between 5-15 seconds).

  • Only the first operation is slow when the TSL is being loaded.
  • Additional operations are faster when the TSL is already in memory.
  • TSL is loaded lazily - only when necessary. Creating new containers or opening containers without signatures does not trigger TSL download.
  • It is possible to load TSL separately (e.g. in application startup) by calling configuration.getTSL().refresh();. This triggers TSL download and later operations (validations, signature creations) would not need to download TSL.
  • TSL is downloaded once a day by default. It takes about 5-15 seconds to load.
  • Make sure to use only one instance of the Configuration object. TSL is stored within the Configuration object memory.
  • See the performance tests results of the library's operation times.

How to add trust for new EU TSL signing certificates?

Trusted EU TSL signing certificates are used for validating the signature of the root TSL (i.e. the List of Trusted Lists - LOTL) published by the European Commission.

DigiDoc4j library stores the LOTL signing certificates in a truststore, e.g:

Regular LOTL - TSL without pivot LOTL support

In order to update the truststore for the LOTL signing certificates, do as follows:

  1. Copy the trusted EU LOTL signing certificates from EU Trusted List of Trust Service Providers. The latest trusted EU LOTL signing certificate is published here between Signature->KeyInfo->X509Data->X509Certificate tag. Certificate
  2. Use KeystoreGenerator.java to generate a new truststore with the new certificates.
  3. Use the newly generated truststore with DigiDoc4j:
    • before version 5.0.0: the default truststore location keystore/keystore.jks and password can be modified:
      • using API methods setTslKeyStoreLocation(String) and setTslKeyStorePassword(String)
      • via digidoc4j.yaml configuration file, by using TSL_KEYSTORE_LOCATION and TSL_KEYSTORE_PASSWORD parameters.
    • since version 5.0.0: the default truststore location classpath:truststores/lotl-truststore.p12, password and keystore type can be modified:
      • using API methods setLotlTruststorePath(String), setLotlTruststorePassword(String) and setLotlTruststoreType(String)
      • via digidoc4j.yaml configuration file, by using LOTL_TRUSTSTORE_PATH, LOTL_TRUSTSTORE_PASSWORD and LOTL_TRUSTSTORE_TYPE parameters.

TSL with pivot LOTL support enabled (since version 5.0.0)

Starting from DigiDoc4J version 5.0.0 pivot LOTL support was added and is enabled by default for DigiDoc4J PROD mode.

With pivot LOTL mechanism, only the initial set of LOTL signing certificates need to be trusted. In order to update the truststore for the initial set of LOTL signing certificates, do as follows:

  1. Copy the trusted EU LOTL signing certificates from the annex of the Information related to data on Member States' trusted lists.
  2. Use KeystoreGenerator.java to generate a new truststore with the new certificates.
  3. Use the newly generated truststore with DigiDoc4j:
    • before version 5.0.0: the default truststore location keystore/keystore.jks and password can be modified:
      • using API methods setTslKeyStoreLocation(String) and setTslKeyStorePassword(String)
      • via digidoc4j.yaml configuration file, by using TSL_KEYSTORE_LOCATION and TSL_KEYSTORE_PASSWORD parameters.
    • since version 5.0.0: the default truststore location classpath:truststores/lotl-truststore.p12, password and keystore type can be modified:
      • using API methods setLotlTruststorePath(String), setLotlTruststorePassword(String) and setLotlTruststoreType(String)
      • via digidoc4j.yaml configuration file, by using LOTL_TRUSTSTORE_PATH, LOTL_TRUSTSTORE_PASSWORD and LOTL_TRUSTSTORE_TYPE parameters.

Troubleshooting issues with LOTL signing certificates

Possible errors in log when LOTL is signed with new certificate that DigiDoc4J is not trusting yet: The certificate used to sign this token is not found or not valid!

<Indication>INDETERMINATE</Indication>
<SubIndication>NO_CERTIFICATE_CHAIN_FOUND</SubIndication>
<Errors>The certificate chain for signature is not trusted, there is no trusted anchor.</Errors>
Since DigiDoc4J version 5.0.0
In case the default TSL refresh callback is used, possible errors could include a TslValidationException with error messages Failed to validate <EU> LoTL: ... and/or <EU> LoTL validation failed; indication: INDETERMINATE; sub-indication: NO_CERTIFICATE_CHAIN_FOUND.

How to sign with Estonian Mobile ID or Smart-ID?

It is possible to sign with Mobile ID (MID) or Smart-ID (SID) by using two step external signing process.

  • You need to have a contract with SK ID Solutions AS to use Mobile-ID or Smart-ID services.

  • See MID documentation for MID endpoints specifics.

  • See Smart-ID documentation for SID endpoint specifics.

  • Here's an example of doing two step external signing

  • MID/SID can be used with the following steps:

  1. Get the signer certificate from MID/SID service
  2. Create a container to be signed (using ContainerBuilder)
  3. Calculate digest to be signed (from dataToSign.getDataToSign())
  4. Sign the digest with MID/SID
  5. Finalize the signature (dataToSign.finalize(signatureValue))
  6. Add the signature to the container (container.addSignature(signature))

How to test with Mobile-ID or Smart-ID

  • If you want to test with your production Mobile-ID or Smart-ID then you have to test in the production (PROD) mode.
  • If you want to test in the TEST mode, then you have to use demo Mobile-ID numbers, which can be found here or either demo Smart-ID app or demo test numbers for Smart-ID.
  • It is NOT possible to test in the TEST mode using production Mobile-ID/Smart-ID (since version 3.1.0).

Using DDoc containers in multi-threaded environment

Since DigiDoc4j uses jDigidoc library for handling DDoc containers, then it has the same problems that using jDigidoc has in multi-threaded environment. DigiDoc4j has solved most of those issues internally, but it is highly recommended to use a different temporary directory for each DDoc container, especially when opening existing containers.

  • Use ContainerBuilder.usingTempDirectory(String path) to specify a temporary directory for opening existing DDoc containers. The path should be unique for each container.
  • It is possible to initialize jDigidoc's ConfigManager manually (if you really need to) by calling ConfigManagerInitializer.forceInitConfigManager. Note that this is not a thread-safe operation, i.e. if multiple threads are handling DDoc containers at the same time, then calling this operation can cause weird side-effects. Use it wisely. Also note that it is not necessary to call this operation in normal circumstances, because DigiDoc4j already handles it by calling it only once and during initialization of the first DDoc container.

Does it really download all the TSL files every time?

  • Quick answer: No
  • Slightly longer answer: it uses caching so all the TSL files are downloaded only once and refreshed when necessary (when they expire).
  • If you are interested in seeing if cached files are used or not, then this information is logged with the Debug level in the underlying DSS library by eu.europa.esig.dss.service.http.commons.FileCacheDataLoader class. It is possible to enable logs by adding the following line <logger name="eu.europa.esig.dss.service.http.commons.FileCacheDataLoader" level="DEBUG"/> to the logback.xml file.

How to clear TSL cache?

  • If you discover that the trusted certificates (like root CA, Timestamp etc) are not updated, then it might help to clear TSL cache.
  • TSL is cached in the temp directory set with the java.io.tmpdir property: java.io.tmpdir/digidoc4jTSLCache
  • Depending on your operating system, the default java.io.tmpdir property may point to
  • /tmp/digidoc4jTSLCache on Linux
  • C:\Users\_admin_\AppData\Local\Temp\digidoc4jTSLCache i.e. %TEMP% on Windows
  • Somewhere obscure like /var/folders/_4/8979h_s11kvbylb3d5p_fydm0000gn/T/ on OSX.
  • Just delete all files stored in the directories

Getting an error while trying to test

  • If you get an error like this java.io.FileNotFoundException: test-tsl/trusted-test-mp.sha2 (or trusted-test-mp.xml)
  • Then take a look at this
  • We do not include test certificates in DigiDoc4j jar file so it must be configured separately.
  • Great Harm may happen if someone uses test certificates in production.

Using a YAML file for configuration

  • It is possible to configure DigiDoc4j using digidoc4j.yaml file (in addition to setting parameters in the Configuration class). Always take version specific digidoc4j.yaml from Github as base, some parameters are mandatory by version.
  • "TEST" mode tries to find digidoc4j-test.yaml file first; if no such file is found, digidoc4j.yaml file is used
  • Default digidoc4.yaml file contains the minimum required configuration. Note that the default configuration contains both production and test certificates for DDOC.
  • This digidoc4j.yaml example contains all the possible configuration parameters.

How to configure logging?

For logging, DigiDoc4j uses SLF4J (Simple Logging Facade for Java). Any dependencies of specific logging frameworks (namely logback) have been removed from the library since version 4.0.0. This means that in order to get DigiDoc4j to log anything, a binding to a specific logging framework of choice must end up in the classpath.

In order to drive logging of validation results, the configuration context is supplemented with a configuration parameter called "PrintValidationReport". This flag controls whether to print validation report result into dedicated log stream. By default this is inactive for "PROD" mode and active for "TEST" mode. Use configuration.setPrintValidationReport method or "PRINT_VALIDATION_REPORT" parameter in "yaml" file to change this behaviour.

Examples of providing logging frameworks by driving application

Logback

In order to use logback with DigiDoc4j, the driving application must include the following dependencies:

  • ch.qos.logback:logback-classic
  • ch.qos.logback:logback-core

For example:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>

Additionally, a configuration file such as logback.xml must be available in the classpath. More information about configuring logback can be found here.

Log4j

In order to use log4j with DigiDoc4j, the driving application must include the following dependencies:

  • org.slf4j:slf4j-log4j12
  • log4j:log4j

For example:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.26</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

Additionally, a configuration file such as log4j.properties must be available in the classpath. More information about configuring log4j can be found here.

Log4j2

In order to use Log4j 2 with DigiDoc4j, the driving application must include the following dependencies:

  • org.apache.logging.log4j:log4j-api
  • org.apache.logging.log4j:log4j-core
  • org.apache.logging.log4j:log4j-slf4j-impl

For example:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.13.0</version>
</dependency>

Additionally, a configuration file written in either XML, JSON, YAML or properties format must be present in the classpath. More information about configuring Log4j 2 can be found here.

Logging before 4.0.0

Before DigiDoc4j version 4.0.0, logback dependencies were included in the library by default. This means that there is no need to include any logging dependencies explicitly when using older versions. Only the logback configuration file must be provided.

Alternatively, the transitive dependancies ch.qos.logback:logback-classic and ch.qos.logback:logback-core could be excluded from DigiDoc4j and then another logging framework of choice provided as described above.

Which file extension to use?

  • If you are creating signatures with SignatureProfile.LT or SignatureProfile.LTA, then use .asice file extension.
  • If you are saving old TimeMark-based containers which have been signed with SignatureProfile.LT_TM, then use .bdoc file extension.

The application which is using DigiDoc4J fails on a clean shutdown?

A new shutdown hook was introduced in release 2.1.0 for shutting down executor services and TSL validation job to provide cleaner application. Please read the documentation of ShutdownHook for a suggestion on how to act accordingly depending on the circumstances.

Getting an IllegalArgumentException (from release 2.1.1 onward) or SAXNotRecognizedException (manifested in 4.0.0-RC.1)

If you get exceptions like:

  • java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD
  • org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.

Then:

  • Be sure that your integration doesn't use Xalan or XercesImpl dependencies and uses a patched Java version (JDK7u40+, JDK8 or higher).
  • Xalan and XercesImpl were used to patch XML vulnerabilities in older java versions. They should be discarded with higher versions because they override default Java XML security.
  • If it is not possible to remove Xalan, then you can set your system property to override TransformerFactory : System.setProperty("javax.xml.transform.TransformerFactory","com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl")

Usage of AIA OCSP for TimeStamp based ASIC-E containers (since release 3.1.0)

It is possible to use automatic AIA OCSP selection for signatures made with LT or LTA profile.

Since DigiDoc4j version 5.3.0, AIA OCSP usage is enabled by default. To disable automatic AIA OCSP usage programmatically, the following parameter must be set: configuration.setPreferAiaOcsp(false);. To disable it through digidoc4j.yaml, add PREFER_AIA_OCSP: false to the configuration.

Prior to DigiDoc4j version 5.3.0, the OCSP URL given in configuration (default is http://ocsp.sk.ee/) was used by default. To enable automatic AIA OCSP usage programmatically, the following parameter must be set: configuration.setPreferAiaOcsp(true);. To enable it through digidoc4j.yaml, add PREFER_AIA_OCSP: true to the configuration.

AIA OCSP responders for Estonia return the certificate status "GOOD" for certificates that have expired. DigiDoc4j checks for certificate expiration prior to making the OCSP request, therefor no AIA OCSP requests are made for expired certificates.

When the feature is turned on then:

  • AIA OCSP URL will be searched from certificate
  • If certificate does not have given AIA OCSP URL (older certificates may not have this), then the correct AIA OCSP URL is selected from the list of default AIA OCSP-s:
    • since version 4.0.0-RC.1, two separate default lists of live and demo AIA OCSP-s are used, which could be complemented or augmented via digidoc4j.yaml file (examples of how to configure AIA OCSP-s via digidoc4j.yaml file can be seen in the aforementioned default files).
    • prior to version 4.0.0-RC.1, this list came from the digidoc4j.yaml file. NB! please use the latest pre-4.0.0 digidoc4j.yaml together with your implementation, otherwise the OCSP fetching will fail in this step.
  • If a match is not found in digicod4j.yaml, default OCSP is used:
    • the OCSP URL configured via the setOcspSource(String) method of the Configuration class or the OCSP_SOURCE configuration parameter in digidoc4j.yaml
    • or the default URL http://ocsp.sk.ee/ (or http://demo.sk.ee/ocsp for TEST mode) if no OCSP URL is explicitly configured

Enforcement of SSL certificates validation (since version 4.0.0-RC.1)

Since version 4.0.0-RC.1, validation of SSL certificates is enforced. This means that Digidoc4J can open secure connections to trusted servers only. If not explicitly configured, Java uses its own default truststore for secure connections. This can be overridden in Digidoc4J by configuring SSL truststore via digidoc4j.yaml:

SSL_TRUSTSTORE_PATH: path/to/custom/ssl/truststore.p12
SSL_TRUSTSTORE_PASSWORD: custom-ssl-truststore-password
SSL_TRUSTSTORE_TYPE: PKCS12

Or programmatically through Configuration object:

configuration.setSslTruststorePath("path/to/custom/ssl/truststore.p12");
configuration.setSslTruststorePassword("custom-ssl-truststore-password");
configuration.setSslTruststoreType("PKCS12");

Additionally, SSL settings can be configured separately for each supported connection type (TSL, OCSP and TSP), by prefixing the YAML parameter with either TSL_, OCSP_ or TSP_, or using the overloaded setSsl*For() methods which take the type of the connection as their first argument. SSL configuration for specific connection types overrides the generic SSL configuration (if present).

Default TLS protocols and cipher suites (since version 5.1.0)

Since version 5.1.0, DigiDoc4j default configuration files digidoc4j.yaml and digidoc4j-test.yaml contain default TLS configuration. This enables both TLSv1.2 and TLSv1.3 for all outbound connections, as well as enforces a recommended set of cipher suites.

As per the Cryptographic Algorithms Lifecycle Report from 2021, using AES-GCM and ChaCha20-Poly1305 cipher suites are recommended. Because the minimum Java version for DigiDoc4j is Java 8, which does not support ChaCha20-Poly1305 cipher suites, the default set of enabled cipher suites for outbound connections in the current version of DigiDoc4j is:

  • for TLSv1.3:
    • TLS_AES_128_GCM_SHA256
    • TLS_AES_256_GCM_SHA384
  • for TLSv1.2:
    • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

In case Java 11 or newer is used for running DigiDoc4j, ChaCha20-Poly1305 cipher suites can be enabled by defining them in a custom digidoc4j.yaml file:

  • for TLSv1.3:
    • TLS_CHACHA20_POLY1305_SHA256
  • for TLSv1.2:
    • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
    • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

NB: When using your own custom configuration files for DigiDoc4j (digidoc4j.yaml and/or digidoc4j-test.yaml), it is advisable to also include the recommended TLS configuration in order to avoid allowing any insecure cipher suites!

NB: When receiving an error "Received fatal alert: protocol_version" when loading the LOTL or any of the Trusted Lists, it may indicate that the server that hosts the problematic Trusted List supports only such TLS protocol versions that are currently not enabled for the outbound connections.

DigiDoc4j version 5.0.0 and older / custom TLS protocol configuration
In case a Trusted List is hosted on a server that supports TLSv1.3 only, make sure that you have set the default protocol to TLSv1.3 and supported protocols to TLSv1.2 and TLSv1.3 either via your DigiDoc4j configuration file or via the setSslProtocol* and setSslProtocols* methods in the Configuration class.

Custom TSL SSL truststore

In case the default SSL truststore that comes with Java is not suitable for TSL loading for some reason, a custom TSL SSL truststore can be configured. DigiDoc4J 4.X.X versions come with their own custom TSL SSL truststore which is applied by default. Since version 5.0.0 this custom truststore has been removed and DigiDoc4J uses the default Java truststore by default again for TSL loading.

DigiDoc4j version 4.X.X
The server certificate of the Estonian trust list used to not be trusted by the default truststore that comes with Java, so Digidoc4J 4.X.X versions come with their own TSL SSL truststore which is applied in "PROD" mode by default. This truststore contains the CA certificates of each European country's national Trusted List providers that serve their lists over a secure connection. The truststore also includes the CA certificate for the EU List of Trusted Lists (LOTL) itself.

Specifying a custom SSL truststore for TSL loading only, can be done via digidoc4j.yaml:

TSL_SSL_TRUSTSTORE_PATH: path/to/custom/ssl/truststore.p12
TSL_SSL_TRUSTSTORE_PASSWORD: custom-ssl-truststore-password
TSL_SSL_TRUSTSTORE_TYPE: PKCS12
DigiDoc4j version 4.X.X
When using custom digidoc4j.yaml configuration file and needing to use the default TSL (in "PROD" mode), one must also include DigiDoc4J-provided TSL SSL truststore configuration in their custom digidoc4j.yaml file. An example TSL SSL truststore configuration can be seen in the default digidoc4j.yaml configuration file. NB: DigiDoc4J-provided TSL SSL truststore must not be used in "TEST" mode with default test TSL, as this truststore does not contain SSL certificates for the default test TSL; for "TEST" mode, separate digidoc4j-test.yaml can be used without the need to explicitly configure any TSL SSL truststore.

This can also be done programmatically through Configuration object:

configuration.setSslTruststorePathFor(ExternalConnectionType.TSL, "path/to/custom/ssl/truststore.p12");
configuration.setSslTruststorePasswordFor(ExternalConnectionType.TSL, "custom-ssl-truststore-password");
configuration.setSslTruststoreTypeFor(ExternalConnectionType.TSL,"PKCS12");

In case of needing to create a custom TSL SSL truststore (or really any SSL truststore for any connection types), one can populate the truststore with either (depending on one's needs):

  • specific server certificates of trusted servers
  • CA certificates (either immediate CA-s or any intermediate CA-s) under which the server certificates of the trusted servers have been issued from
  • root certificates under which the CA-s of the trusted server certificates have been issued from
DigiDoc4j version 4.X.X / custom truststore users
Estonian TSL SSL certificate was last updated on 16.08.2023 to new certificate issued by DigiCert Global G2 TLS RSA SHA256 2020 CA1. Neither the CA nor its root certificate (DigiCert Global Root G2) is trusted by the default Digidoc4j truststores of 4.X.X versions. So, in case of using either a 4.X.X default truststore or a custom truststore to manage the certificates by yourself, the truststore must be updated in order to be able to use the Estonian trusted list.

NB: When receiving an error "Unable to process GET call for url [...]. Reason : [PKIX path building failed: ...: unable to find valid certification path to requested target]" when loading the LOTL or any of the Trusted Lists for required countries, it may indicate that the server hosting the requested resource is not trusted by DigiDoc4j.

Updating a custom TSL SSL truststore

When using a custom truststore or the TSL truststore that comes with DigiDoc4j 4.X.X versions, it may be occasionally necessary to update this truststore in case any of the national Trusted List providers or the EU LOTL provider change anything about how or where they serve their content from. To make this task easier, a command line tool TLS Truststore Generator can be used. This tool gathers currently used certificates from TSL. For adding certificates proactively, a keytool or similar can be used.

An example of generating a PKCS12 truststore with password changeit from the EU LOTL containing the CA (or the certificate itself if no CA is available) of each national Trusted List provider (and EU LOTL provider itself) who serve their content over a secure connection:

java -jar tls-truststore-generator-1.0.0.jar --lotl-url https://ec.europa.eu/tools/lotl/eu-lotl.xml --follow-redirects --extract-from-chain ca-or-cert --type PKCS12 --password changeit --out /path/to/tsl_ssl_truststore.p12

More information about how to use the command line tool can be found here.

Custom data loaders (since version 4.0.0-RC.1)

In the light of the enforcement of SSL certificates validation, DigiDoc4j version 4.0.0-RC.1 also added the possibility to provide custom data loaders for various operations - loading TSL, making timestamp and OCSP requests - in order to make it possible to bypass and/or enhance the default behaviour.

Version 4.0.0, which fixed the issue of redirects not being followed when accessing AIA certificate sources, also added the possibility to provide a custom data loader for accessing AIA certificate sources.

Providing custom data loaders is done via DataLoaderFactory interface whose implementations can be registered in the Configuration object via the following methods:

  • setTslDataLoaderFactory(DataLoaderFactory) for loading TSL (deprecated in version 5.0.0)
  • setTspDataLoaderFactory(DataLoaderFactory) for making timestamp requests
  • setOcspDataLoaderFactory(DataLoaderFactory) for making OCSP requests
  • setAiaDataLoaderFactory(DataLoaderFactory) for accessing AIA certificate sources (deprecated in version 5.1.0)

Custom TSL file loader (since version 5.0.0)

Starting from DigiDoc4j version 5.0.0, configuring custom data loaders for loading TSL is deprecated. The preferred way to provide custom functionality for TSL loading is via the DSSFileLoader interface. Providing custom file loaders is done via DSSFileLoaderFactory interface whose implementations can be registered in the Configuration object via the following method:

  • setTslFileLoaderFactory(DSSFileLoaderFactory) for loading TSL

Configuring custom data loaders for TSL is still supported, but the following must be considered:

  • a custom TSL data loader is applied only if no custom TSL file loader is configured; in case a custom file loader is configured as well, the file loader is prioritized over the data loader
  • in case a custom TSL data loader does not implement the DSSFileLoader interface, it is wrapped into a FileCacheDataLoader which uses the default TSL cache directory and configured TSL cache expiration time; to avoid wrapping the custom data loader, it must implement the DSSFileLoader interface

Custom AIA source (since version 5.1.0)

Starting from DigiDoc4j version 5.1.0, configuring custom data loaders for fetching certificates from AIA URLs is deprecated. The preferred way to provide custom functionality for AIA certificate resolution is via the AIASource interface. Providing custom AIA sources is done via AIASourceFactory interface whose implementations can be registered in the Configuration object via the following method:

  • setAiaSourceFactory(AIASourceFactory) for resolving AIA certificates

Configuring custom data loaders for fetching AIA certificates is still supported, but the following must be considered:

  • a custom AIA data loader is applied only if no custom AIA source is configured; in case a custom AIA source is configured as well, the AIA source is prioritized over the data loader
  • in case only a custom AIA data loader is configured, it is wrapped into the DefaultAIASource implementation

How to configure Digidoc4j to use proxy servers

Digidoc4j's default data loaders can be configured to use proxies either via digidoc4j.yaml:

# HTTP proxy
HTTP_PROXY_HOST: proxy.host
HTTP_PROXY_PORT: 1234
# HTTPS proxy
HTTPS_PROXY_HOST: proxy.host
HTTPS_PROXY_PORT: 1234

Or programmatically through Configuration object:

// HTTP proxy
configuration.setHttpProxyHost("proxy.host");
configuration.setHttpProxyPort(1234);
// HTTPS proxy
configuration.setHttpsProxyHost("proxy.host");
configuration.setHttpsProxyPost(1234);

Additionally, proxy settings can be configured separately for each supported connection type (TSL, OCSP and TSP), by prefixing the YAML parameter with either TSL_, OCSP_ or TSP_, or using the overloaded set*Proxy*For() methods which take the type of the connection as their first argument. Proxy configuration for specific connection types overrides the generic proxy configuration (if present).

NB: If both HTTP (usually TSP and OCSP requests, some trust lists) and HTTPS (European LOTL and most trust lists) connections must be established through proxies, then both HTTP and HTTPS proxy configurations must be present! The same proxy server can be used for both. For HTTPS, the proxy server must support HTTP CONNECT method.

Proxy user and password can be configured either via digidoc4j.yaml:

HTTP_PROXY_USER: user
HTTP_PROXY_PASSWORD: password
# Since version 5.0.0, HTTPS proxy user and password are separately configurable
HTTPS_PROXY_USER: user
HTTPS_PROXY_PASSWORD: password

Or programmatically through Configuration object:

configuration.setHttpProxyUser("user");
configuration.setHttpProxyPassword("password");
// Since version 5.0.0, HTTPS proxy user and password are separately configurable
configuration.setHttpsProxyUser("user");
configuration.setHttpsProxyPassword("password");

Additionally, separate configuration for each supported connection type (TSL, OCSP and TSP) is possible by prefixing the YAML parameter with either TSL_, OCSP_ or TSP_, or using the overloaded set*Proxy*For() methods which take the type of the connection as their first argument. Configuration for specific connection types overrides the generic proxy configuration (if present).

NB: Starting from DigiDoc4j version 5.0.0, proxy user and password are separately configurable for HTTP and HTTPS! When migrating to version 5.0.0 from earlier versions and custom configuration for proxy user and password is used, then additional configuration for HTTPS needs to be added! Prior to version 5.0.0, the user and password were not separately configurable for HTTP and HTTPS, and methods and configuration parameters with the HTTP prefix affected both HTTP and HTTPS proxy user and password.

Proxying is not supported by the default data loader for accessing AIA certificate sources! In order to access AIA certificate sources via proxies, a custom data loader must be configured to be used for that. More information about using custom data loaders can be read from above. As an example, DSS CommonsDataLoader can be used for more configurability options, including proxy usage. NB: different data loaders can affect performance differently!

Getting an ExceptionInInitializerError because of incompatible BouncyCastle version (since version 4.0.0-RC.1)

Currently the underlying DSS library does not support BouncyCastle versions 1.64 and up. The DSS version used in Digidoc4J was itself developed against BouncyCastle 1.62, but 1.63 also seems to work.

At the time of writing, the aforementioned incompatibility was known to affect only validation of signatures containing encapsulated CRL data.

Getting ZIP-bombing detection errors on opening ZIP-based containers (since version 4.2.0)

In Digidoc4J version 4.2.0, rudimentary ZIP-bombing detection was introduced. This resulted in getting the following error while parsing a ZIP-file-based container that was considered harmful:

Zip Bomb detected in the ZIP container. Validation is interrupted.

In version 4.2.1, ZIP-bombing detection was improved and made configurable. Currently, the following parameters are configurable:

  • Maximum allowed compression ratio - how many times are the contents of a ZIP-based container allowed to expand on unpacking (compared to the original size of the container) before the container is considered harmful. Defaults to 100 if not changed.
  • Compression ratio check threshold - how much memory are the unpacked contents of a ZIP-based container allowed to consume before the ZIP compression ratio check kicks in. Meaning that the previously described compression ratio check is not performed as long as the size of the unpacked contents of a container is less than this value. Defaults to 1 MB (1048576 bytes) if not changed.

The described parameters can be configured either via digidoc4j.yaml:

MAX_ALLOWED_ZIP_COMPRESSION_RATIO: 100
ZIP_COMPRESSION_RATIO_CHECK_THRESHOLD_IN_BYTES: 1048576

Or programmatically through Configuration object:

configuration.setMaxAllowedZipCompressionRatio(100);
configuration.setZipCompressionRatioCheckThresholdInBytes(1048576L);

In case there is a need to completely disable ZIP-bombing detection, then increasing the threshold parameter to some value above the amount of memory that your system allows Digidoc4J to allocate, will effectively disable the ZIP-bombing check. The maximum allowed value for the threshold is Long.MAX_VALUE.

NB: When reading containers from input streams (instead of files), then the total size of the container is not known in advance and must be calculated on the fly while the stream is read. This makes the unpacked container contents size and the total container size ratio calculation inaccurate and can balloon the ratio way over the expected limit if heavily compressed files are located at the beginning of the container. When reading containers from input streams, then depending on the container and its contents, higher ZIP-bombing detection ratio and/or threshold might be needed to be configured.

Unexpected behavior on creating or opening different types of containers concurrently (since version 2.0.0, fixed in version 4.3.0)

ContainerBuilder instances share mutable state which may cause unexpected behaviour while concurrently using multiple ContainerBuilder instances which have been created for different container types. This problem has been present since version 2.0.0 but may be more problematic after version 3.1.1 when stricter rules between BDOC and ASICE container types were defined.

As a temporary workaround, it is possible to use syncronized block on ConatainerBuilder class, but it must be ensured that the block is used from .aContainer(...) call till the .build() call and the same ContainerBuilder instance can not be reused.

This problem has been fixed in Digidoc4j version 4.3.0.

TSL refresh callbacks (since version 5.0.0)

Starting from DigiDoc4J version 5.0.0, a configurable mechanism was added for validating the internal state of the TSL after it has been refreshed in DigiDoc4J. A TSL refresh refers to either the initial download, parsing and validation of LOTL and national Trusted Lists, or subsequent repetitions of the same actions triggered by either a manual refresh or an access to the internal TSL by a signing or a validation process after the internal state of the TSL has expired.

A TSL refresh callback is an implementation of the TSLRefreshCallback functional interface which accepts an instance of TLValidationJobSummary and returns either a boolean or throws an exception:

public interface TSLRefreshCallback extends Serializable {
  boolean ensureTSLState(TLValidationJobSummary summary);
}
  • The callback should throw an exception in case the TSL is not considered to be in a valid and/or usable state after a refresh. An exception stops any further processing of the process that triggered the refresh - either a TSL updater process which has triggered the refresh manually, or a signing or validation process which has accessed the TSL after its internal state has expired.
  • The callback should return false in case the TSL is considered in a good enough state that the process which triggered the refresh may continue, but the internal state of the TSL must remain being marked as expired - the next TSL access will trigger a refresh again for an expired TSL. NB: Use with caution! The TSL could be accessed multiple times during the creation or validation of a single signature - as long as the internal state of the TSL remains being marked as expired, each of such accesses will trigger the refresh again!
  • In all other cases, the callback should return true, meaning that the TSL is in a good state and no refresh is required until the next time the internal state of the TSL expires again.

A custom TSL refresh callback can be specified via the setTslRefreshCallback(TSLRefreshCallback) method of the Configuration class. In case no custom callback is specified, a default callback is used. The default callback behaves in the following manner:

  • Throws a TslRefreshException (or any of its subclasses) in case:
    • the LOTL has failed to download, parse or validate successfully, regardless of whether this was an initial or a subsequent TSL refresh.
    • a Trusted List of a required territory* has failed to download, parse or validate successfully, regardless of whether this was an initial or a subsequent TSL refresh.
    • no Trusted Lists of a LOTL have downloaded, parsed and validated successfully, regardless of whether this was an initial or a subsequent TSL refresh.
  • Returns true in all other cases.

* The list of required territories can be specified either via digidoc4j.yaml:

REQUIRED_TERRITORIES: EE, LV, LT

Or programmatically through Configuration object:

configuration.setRequiredTerritories("EE", "LV", "LT");

The default required territory for "PROD" mode is EE. No required territories are set by default for "TEST" mode. The format of required territories shall adhere to the same rules as trusted territories.

NB: In case the list of trusted territories has also been configured (i.e. the list of trusted territories is not empty), then the default TSL refresh callback skips the enforcement of those required territories which are not specified in the list of trusted territories!

Validate TSL state after manual refresh only

In case the application using DigiDoc4J is built to trigger TSL refreshes explicitly, and the validation of the internal state of the TSL should be performed only after such manual refreshes, then a custom NO-OP TSL refresh callback could be specified:

// Configure a custom TSL refresh callback for the central Configuration object
configuration.setTslRefreshCallback(summary -> true);

Each time when performing the explicit refresh manually, then the information about the internal state of the TSL can be queried afterwards, and this information can be used to decide any further actions (whether the TSL is good, the refresh must be re-tried or some other action is needed):

// Trigger a TSL refresh manually
configuration.getTSL().refresh();
// Acquire the state of the last TSL refresh
TLValidationJobSummary summary = configuration.getTSL().getSummary();
// Use the summary to decide whether the TSL is in a valid and usable state,
//  the refresh should be re-tried or some other action must be taken

Use DigiDoc4j in Spring Boot 3 application

It is recommended to use DigiDoc4j version 5.3.0 or newer! DigiDoc4j 5.3.0 is based on DSS 6.0 which uses Jakarta XML Binding API instead of the old Javax XML Binding API.

If, for some reason, it is not possible to upgrade to DigiDoc4j 5.3.0, it must be ensured that all the dependencies in your application that DigiDoc4j uses, are compatible with the specific versions of DigiDoc4j (and DSS). Depending on the DigiDoc4j version that your application uses, you might need to strip DigiDoc4j of its Jakarta dependencies and replace them with corresponding Javax dependencies, in order to make DigiDoc4j compatible with your Spring Boot 3 application.

The following example shows how to make DigiDoc4j 5.2.0 work in a simple Spring Boot 3 application (as an example of the contents of the <dependencies> block of a simple Maven project):

<dependency>
    <groupId>org.digidoc4j</groupId>
    <artifactId>digidoc4j</artifactId>
    <version>5.2.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.sun.activation</groupId>
            <artifactId>*</artifactId>
        </exclusion>
        <exclusion>
            <groupId>jakarta.activation</groupId>
            <artifactId>*</artifactId>
        </exclusion>
        <exclusion>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.9</version>
    <exclusions>
        <exclusion>
            <groupId>com.sun.activation</groupId>
            <artifactId>*</artifactId>
        </exclusion>
        <exclusion>
            <groupId>jakarta.activation</groupId>
            <artifactId>*</artifactId>
        </exclusion>
        <exclusion>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

NB: Experience may vary depending on your application and the version of DigiDoc4j you are using, and additional tweaking might be needed!

Clone this wiki locally