Skip to main content
Version: v0.25.0 (Latest)

ETSI Trust Lists

The IDK supports two ETSI trust list standards for validating trust service providers within the European Union and beyond. Trust lists publish structured information about which organizations are authorized to provide trust services such as issuing qualified certificates, timestamps, and electronic seals.

Standards Overview

The IDK implements two complementary ETSI standards:

StandardFormatDescription
ETSI TS 119 612XML (TSL)Trust Service Status Lists, the original XML-based format used by EU member states
ETSI TS 119 602JSON (LoTE)List of Trusted Entities, a newer JSON-based format for publishing trusted entity information

Both formats describe the same conceptual model: a hierarchy of trust lists that enumerate authorized trust service providers, their services, and the current status of each service. The ETSITrustListResolver loads either format and normalizes it into the ETSILoTE domain model.

Trust List Hierarchy

The European Commission publishes a List of Trusted Lists (LOTL), a master index that points to each EU member state's individual trusted list. Each member state list enumerates the qualified trust service providers (QTSPs) operating under that country's supervision.

EU LOTL Hierarchy

The well-known URL for the EU LOTL is:

https://ec.europa.eu/tools/lotl/eu-lotl.xml

Architecture

The ETSI trust integration consists of two main components:

  • ETSITrustValidator: a trust validation service that extends AbstractTrustValidationService("etsi_tsl") and is contributed into the session scope via @ContributesIntoSet(SessionScope::class). It uses TrustContext.TYPE_ETSI_TSL to identify itself within the trust framework.
  • ETSITrustListResolver: loads and parses trust lists from HTTP/HTTPS URIs. For XML-format lists (TS 119 612), it verifies XML signatures before processing. Returns the parsed data as an ETSILoTE domain model regardless of the source format.

Loading Trust Lists

The ResolveEtsiTrustListCommand (command ID: trust.etsi.resolve) loads trust lists from a URI and optionally resolves the full LOTL hierarchy.

val trustService = session.graph.etsiTrustValidator

// Resolve the EU LOTL and all member state lists
val result = trustService.resolve(
trustListUri = "https://ec.europa.eu/tools/lotl/eu-lotl.xml",
resolveLotl = true,
territories = listOf("NL", "DE", "FR"), // Optional: filter by country
verifySignatures = true
)

println("Trust lists loaded: ${result.trustListCount}")
println("Territories covered: ${result.territories}")
println("Total services found: ${result.totalServices}")

The ResolveEtsiTrustListResult returned by the resolve operation contains:

FieldTypeDescription
trustListCountIntNumber of trust lists loaded
territoriesList<String>ISO 3166-1 alpha-2 country codes covered
totalServicesIntTotal number of trust services across all lists

When resolveLotl is true, the resolver follows the LOTL pointers to download each member state list. When false, only the single list at trustListUri is loaded. The optional territories filter limits which member state lists are fetched, which reduces load time when you only need a subset of countries.

Validating Against Trust Lists

The ValidateEtsiTrustCommand (command ID: trust.etsi.validate) checks whether a given identifier is present in a loaded trust list and whether the associated service has an acceptable status.

val trustService = session.graph.etsiTrustValidator

// Validate an identifier against ETSI trust lists
val validationResult = trustService.validate(
trustListUri = "https://ec.europa.eu/tools/lotl/eu-lotl.xml",
identifierJson = identifierJsonString,
checkRevocation = true,
territory = "DE" // Optional: restrict to a specific territory
)

if (validationResult.trusted) {
println("Entity is trusted")
println("Provider: ${validationResult.providerName}")
println("Service status: ${validationResult.serviceStatus}")
} else {
println("Entity not found in trust lists")
}

Identifier Resolution Integration

The ETSI trust module integrates with the IDK's identifier resolution system through two identifier methods:

Identifier MethodPurpose
ETSI_TSLResolve identifiers against ETSI Trust Service Status Lists
ETSI_TSPResolve identifiers for specific Trust Service Providers

These methods use ExternalIdentifierETSITslOpts for input configuration and return ExternalIdentifierETSITslResult with the matched trust information. This allows ETSI trust lookups to be composed with other identifier resolution strategies in a uniform way.

Service Status Values

Each trust service in a list carries a status value indicating whether it is currently authorized to operate. The IDK recognizes the following ETSI-defined status values:

StatusMeaning
GRANTEDThe service is currently authorized and active. This is the primary "good" status.
WITHDRAWNThe service authorization has been permanently withdrawn by the supervisory body.
DEPRECATEDThe service is deprecated. It may still be technically valid but is no longer recommended.
RECOGNISED_NATIONAL_LEVELThe service is recognized at the national level but does not hold EU-wide qualified status.
REVOKEDThe service has been revoked due to a compliance or security issue.
SUSPENDEDThe service is temporarily suspended pending investigation or remediation.

When validating, you should generally treat GRANTED as trusted. Whether to accept RECOGNISED_NATIONAL_LEVEL depends on your application's requirements; it indicates national-level trust without full EU qualification.

// Check the status of a resolved service
when (service.status) {
ServiceStatus.GRANTED -> {
// Fully authorized - safe to trust
}
ServiceStatus.RECOGNISED_NATIONAL_LEVEL -> {
// National trust only - decide based on your policy
}
ServiceStatus.WITHDRAWN,
ServiceStatus.REVOKED,
ServiceStatus.SUSPENDED -> {
// Do not trust
}
ServiceStatus.DEPRECATED -> {
// Valid but discouraged - check validity period
}
}

XML Signature Verification

Trust lists published in the ETSI TS 119 612 XML format are digitally signed by the scheme operator. The IDK verifies these signatures automatically during loading to prevent tampering.

The XmlSignatureVerifier interface (implemented by XmlUtilSignatureVerifier) supports two signature formats:

FormatStandardDescription
XAdESETSI TS 101 903XML Advanced Electronic Signatures, the format used by most EU trust lists
XmlDSigW3C XML SignatureBase XML Digital Signature format

Signature verification produces an XmlSignatureVerificationResult:

FieldTypeDescription
validBooleanWhether the signature is cryptographically valid
signaturePresentBooleanWhether a signature was found in the document
signingTimeInstant?When the document was signed, if available
xadesPropertiesXadesProperties?Additional XAdES properties such as signing certificate info

Signature verification is enabled by default. You can disable it for development or testing by setting verifySignatures = false in the resolve call, but this should never be done in production.

Configuration

Configure ETSI trust list behavior through the EtsiTrustConfig properties:

# Enable ETSI trust list support (disabled by default)
trust.anchors.etsi.enabled=false

# URL for the EU List of Trusted Lists
trust.anchors.etsi.lotl-url=https://ec.europa.eu/tools/lotl/eu-lotl.xml

# Verify XML signatures on trust lists (recommended: true)
trust.anchors.etsi.verify-signatures=true

# Optional: restrict to specific territories (comma-separated ISO 3166-1 alpha-2 codes)
trust.anchors.etsi.territories=NL,DE,FR

Caching

Trust lists are large XML documents that change infrequently (typically updated every 6 months by member states). The IDK caches loaded trust lists with a default TTL of 60 minutes. After the TTL expires, the next access triggers a background reload.

This means the first load incurs network latency, but subsequent validations within the TTL window are served from the in-memory cache without any HTTP requests.

Module Dependencies

To use ETSI trust list functionality, include the trust module in your project:

// build.gradle.kts
dependencies {
implementation("com.sphereon.idk:lib-trust-etsi:<version>")
}

The ETSI trust module depends on:

  • lib-trust-api: core trust validation interfaces (AbstractTrustValidationService, TrustContext)
  • lib-crypto-core-public / lib-crypto-core-impl: cryptographic primitives for signature verification
  • lib-http-client: HTTP client for downloading trust lists from remote URIs