European Union List of Trusted Lists in Validation
European Union List of Trusted Lists Explanation
The European Union's List of Trusted Lists (LOTL), is a central, signed XML file that contains links to the individual trusted lists published by each EU and EEA Member State. These Member State lists identify trust service providers and the trust services they offer, such as digital signatures and seals, ensuring their compliance with EU eIDAS regulations and facilitating the validation of electronic signatures.
In simple terms, European Union List of Trusted Lists (LOTL in future references) is an XML file, which contains country specific Trusted Lists (TL). Those country specific TLs contain various certificates, which are considered trustworthy and can be used during PDF signature validation.
However a responsible validation processor should not just download those certificates, without confirming the source itself is trusted. For that purpose both the main LOTL file and country-specific TLs are signed. Trusted certificates mentioned in those TLs are only supposed to be trusted, if the corresponding XML files are successfully validated.
And now we are happy to announce, iText supports retrieval, validation and usage of European Union List of Trusted Lists!
Why this may be useful
In order to be able to validate anything signature related, a chain of trust must be established. Without going too deep into the details, eventually any chain of trust ends with some kind of certificate which is supposed to be unconditionally trusted.
Before this feature was introduced, users were forced to provide trusted certificates manually. Even though this is still possible, many may find such a requirement slightly inconvenient. So, now you are not obliged to do that. The European Union List of Trusted Lists can be retrieved, validated and parsed to provide root trusted certificates instead.
API Entry point and overall introduction
In order to start using this feature, the first step would be to enable it in the ValidatorChainBuilder
API. All you need to do is to call the ValidatorChainBuilder#trustEuropeanLotl(boolean)
method with the true
parameter. That’s it. From now on any validation performed with validators, created out of this builder will use European Union Trusted Lists. However, there is one additional step which is required.
Retrieving, parsing and validating huge XML files, containing thousands of certificates is a heavyweight operation, that’s why we don’t want it to happen too often. For exactly this reason iText stores the data in a specific cache. By default this cache is static, and can be accessed from anywhere in your project. This way we minimize processing time and memory consumption as much as possible. That’s why, before Trusted Certificates are used in your validation process, the cache must be initialized.
In order to do so, the static LotlService#initializeGlobalCache(LotlFetchingProperties)
method has to be called. This step is required before any validation with European Union LOTL usage feature takes place. If the cache is not initialized, a corresponding exception will occur.
We strongly advise to perform this operation in advance, so that actual PDF validation takes as little time as possible. We also forbid calling this method a second time, to avoid potential accidental cache re-initialization.
But what are those LotlFetchingProperties
? Well, this is how details of LOTL parsing and usage can be configured. Let’s take a deeper look.
First of all, creation of LotlFetchingProperties
requires IOnFailingCountryLotlData
to be provided as a parameter. This strategy defines the behavior, in case of any country specific sources being unavailable.
It’s important to remember, iText has no influence over external resources being fetched and used in this feature.
Two strategies are already defined in our API. RemoveOnFailingCountryData
and ThrowExceptionOnFailingCountryData
, but of course custom ones can be created to fulfil your specific needs.
RemoveOnFailingCountryData
basically ignores possible failures on country specific TL retrieval and parsing. In case of any failure, the Trusted List is ignored and the process continues.
ThrowExceptionOnFailingCountryData
on the other hand, throws an exception in case of any failure.
And once again, this strategy is only relevant in case of country-specific TL failures. If something else fails, most likely there is no option other than throw an exception, because the whole chain is no longer trusted, so we want to make sure the user is aware of such behavior.
In addition to the strategy, which is required, there are couple of optional configurations.
country names (schema names) - this configuration affects which country-specific TLs are expected to be used. Possible values can be found in the
LotlCountryCodeConstants
class. Both inclusion and exclusion options are provided.service types - this configuration affects which certificates are supposed to be used from Trusted Lists. Each certificate in the list contains service type field, which defines the scope, in which certificate is supposed to be trusted. Some certificates are only expected to be used to sign timestamps or timestamp chains, others are defined for OCSPs, etc… Using this API, user can re-configure, which service types are suppose to be used during the validation. However, we still treat those according to their meaning. To change that, more low-level configuration is required which involves
LotlTrustedStore
override.cache staleness - this configuration defines how stale your data can be, before it can no longer be used. We’ll discuss it in more details a bit later. By default the value is 24 hours.
refresh interval calculator - this function defines, how often your data is supposed to be refreshed. We’ll discuss it in more details soon. By default the value is 23% of staleness
Data Refresh
The next topic we want to address, is how to update LOTL related data. We already mentioned, that it’s not possible to call LotlService#initializeGlobalCache(LotlFetchingProperties)
more than once. We also already established, that data fetch is quite a heavy operation, so we don’t want to do that every time a validation is performed.
For that reason, a cache was created which stores all the data. However, it’s obviously possible that something might change if you run your application for a significantly long time. That’s why it’s important to update the data from time to time. And we take care of this ourselves as well.
Upon first cache initialization, a specialized background task is set up, which periodically performs a cache update. The operation which happens behind the scenes is exactly the same as on first initialization. We just retrieve everything from scratch, parse and validate it, and if everything is fine, update the cache.
By default this happens each 5.52 hours, but this can be configured in LotlFetchingProperties
class by providing a custom refresh interval calculator.
But what happens, if some data is not available at the moment of refreshing? Let’s say we were able to successfully get France’s Trusted Certificates on first initialization, but for some reason we weren’t able to update those on refreshing. You as a user might still want to use old data, at least for some time. This is why we created the staleness parameter.
The staleness parameter can be configured via the LotlFetchingProperties
setting. This parameter establishes the maximum permissible age for data to be considered valid and usable. By default, staleness is set to 24 hours, meaning the data remains usable for that period if refreshing fails.
What will happen after? The very same IOnFailingCountryLotlData
we asked you to provide will be used in case of country-specific data being too stale. For any other, non country-specific data, an exception will be thrown.
Custom configurations for custom validations
Up to this point we have described the creation, initialization, and use of the static LotlService
. That means that only single LotlFetchingProperties
can be provided for such LotlService
. But how can I have multiple different configurations depending on what I want to validate?
Let’s say for one specific validation, only Germany’s certificates should be used, but for another set of documents, Spain’s certificates are needed. Well, in order to have custom validations, custom LotlService
instances can be created.
The ValidatorChainBuilder
API allows you to provide your own LotlService
instances with ValidatorChainBuilder#withLotlService
. By default, a statically defined one is used.
So if you want to have multiple different LOTL configuration, just create multiple LOTL Services with different LotlFetchingProperties
, initialize those by calling LotlService#initializeCache
and your are good to go.
Just remember, each LotlService
uses it’s own cache, so be careful not to store same data multiple times. Additionally, each LotlService
set ups their own refreshing task. That’s why when you are done with specific LotlService
, we need to clean up everything.
For this purpose LotlService
implements AutoCloseable
in Java and IDisposable
in C#. Don’t forget to manage your resources 🙂 .
Root Trusted Certificates for LOTL files
As we’ve already mentioned, LOTL files are presented as signed XML files. In order to be able to validate these, some trusted certificates are needed to establish trust.
But wait, the main idea of a LOTL file is to provide us with trusted certificates. And now you are saying we need more trusted certificates, to validate LOTL files? Well, yes, trusted certificates from the LOTL file cannot be used to validate this exact same LOTL file.
That’s why the European Union additionally shares list of trusted certificates, to be used to validate LOTL files. Those are provided in the Official Journal of the European Union.
iText needs those, but retrieving them from the internet doesn’t sound like a good idea, the Journal isn’t signed, so there is no way to be sure, it wasn’t compromised if you retrieve it on runtime from the internet.
Instead, we pre-downloaded them in a specialized repository. It’s called eu-trusted-lists-resources
and can be found in Maven and NuGet. This repository contains the list of trusted certificates and URL addresses, from which the List of Trusted Lists should be retrieved.
The dependency to this repository is not provided in iText by default, so in order to be able to use LOTL feature, you’ll need to either provide such a dependency, or configure your own source of Official Journal trusted certificates.
In order to configure a custom source, LotlService#withEuropeanResourceFetcher
can be used. You have a choice to either be yourself responsible for providing this source of trust, or rely on iText to do so.
Even though these Journal trusted certificates are meant to remain the same for years, eventually they will be updated as well. If for some reason outdated trusted certificates are used, the LOTL file will not be successfully validated and the whole feature won’t work anymore, that’s why it’s crucial to be able to update those in time.
But don’t worry, this is not going to happen out of the blue. The mechanism of updating involves safe measures, including a transition period, to ensure that users and relying parties have enough time to adjust their code base and resources.
A new version of eu-trusted-lists-resources
library is expected to be released each time those resources are updated. A corresponding exception should be expected to be thrown if the resources are outdated.
However, if LOTL certificates are suddenly no longer successfully validated, please check that the Official Journal trusted certificates are up to date.
Possible problems you may encounter
Since this whole feature strongly depends on a remote infrastructure maintained by European Union parties, iText cannot guarantee complete stability. However, we can instead warn you about possible problems and solutions:
SSLHandshakeException
being thrown on country specific fetching
In order to establish trust for HTTPS connection, Java uses a pre-downloaded list of trusted certificates. Those are embedded in your JDK. However, if the JDK version is not up to date, it might be possible that some certificates are missing and HTTPS connection cannot be trusted.
Because of this, you may suddenly be faced with SSLHandshakeException
or its analogs. There are multiple ways to fix that, ideally you would want to update your JDK to include all the necessary trusted certificates. However, if this is not possible for some reason, there are some alternatives.
Many of those will include the creation of a custom IResourceRetreiver
, which can be set using LotlService#withCustomResourceRetriever
.
WebException
being thrown on country specific fetching
Apart from an SSL certificate not being trusted, there is one more potentially problematic scenario. Some authorities may not allow you to establish a connection if a user agent is not set up.
By default iText uses an empty user agent. This should also be configured through the use of custom IResourceRetreiver
and LotlService#withCustomResourceRetriever
.
Ahead of Time compilation
In the case of the GraalVM JDK there’s a known compatibility issue with the 3rd-party-dependency in GraalVM environment. It’s fairly easy to solve this by providing the missing configurations, which is carefully explained in this article: Supporting org.apache.xml.security in GraalVM.
An additional point relates to the Apache Santuario library, which will not work out of the box and so requires manual adjustment for compatibility with GraalVM. The required configuration options can be found in this commit: GitHub - Finalize LOTL API Add support for GraalVM, however, we are currently working on pushing this to the Oracle GraalVM Reachability Metadata repository.
Samples
As usual, we’ve prepared plenty of samples showcasing different scenarios for LOTL feature usage, which can be found in itext-publications-signing-examples-java and itext-publications-samples-dotnet.