Skip to main content
Version: v0.13

ETSI Trust Lists

The IDK supports ETSI TS 119 612 Trust Service Status Lists (TSL), the standard format used across the European Union for publishing trusted service providers. This enables validation of credentials issued by EU-recognized trust services.

What are ETSI Trust Lists?

ETSI Trust Lists (also called Trusted Lists or TSL) are standardized XML documents that publish information about trust service providers and their services. In the EU, each member state maintains a trusted list of qualified trust service providers (QTSPs) that meet eIDAS regulation requirements.

The EU also maintains a List of Trusted Lists (LOTL), which is a master index pointing to all member state trusted lists.

Trust List Hierarchy

ETSI Trust List Hierarchy

Loading Trust Lists

val trustListService = session.component.trustListService

// Load the EU List of Trusted Lists
val lotl = trustListService.loadLotl(
url = "https://ec.europa.eu/tools/lotl/eu-lotl.xml"
)

// This automatically loads all referenced member state lists
println("Loaded ${lotl.trustedLists.size} member state lists")

// Access a specific country's list
val germanList = lotl.trustedLists.find { it.schemeTerritory == "DE" }
println("German TSPs: ${germanList?.trustServiceProviders?.size}")

Loading Individual Lists

For scenarios where you only need specific country lists:

// Load a single country's trusted list
val germanList = trustListService.loadTrustedList(
url = "https://example.de/tsl.xml"
)

// Inspect the list
println("Territory: ${germanList.schemeTerritory}")
println("Operator: ${germanList.schemeOperatorName}")
println("Version: ${germanList.tslVersionIdentifier}")
println("Sequence: ${germanList.tslSequenceNumber}")
println("Issue Date: ${germanList.listIssueDateTime}")
println("Next Update: ${germanList.nextUpdate}")

Querying Trust Service Providers

// Find all qualified trust service providers
val qualifiedProviders = lotl.findProviders {
status = TrustServiceStatus.QUALIFIED
}

qualifiedProviders.forEach { provider ->
println("Provider: ${provider.name}")
println(" Country: ${provider.schemeTerritory}")
println(" Services: ${provider.services.size}")
}

// Find providers offering specific service types
val signatureProviders = lotl.findProviders {
serviceType = ServiceType.QUALIFIED_CERTIFICATE_FOR_ELECTRONIC_SIGNATURE
}

// Find providers by certificate
val matchingProviders = lotl.findProvidersByCertificate(
certificate = issuerCertificate
)

Trust Service Status

ETSI defines specific status values for trust services:

StatusDescription
GRANTEDService is currently granted/active
WITHDRAWNService has been withdrawn
DEPRECATEDService is deprecated but may still be valid
RECOGNISEDAT NATIONALLEVELRecognized at national level
QUALIFIEDService is qualified under eIDAS
// Check if a service is currently valid
val service = provider.services.first()

when (service.currentStatus) {
TrustServiceStatus.GRANTED,
TrustServiceStatus.QUALIFIED -> {
println("Service is active and trusted")
}
TrustServiceStatus.WITHDRAWN -> {
println("Service has been withdrawn")
}
TrustServiceStatus.DEPRECATED -> {
println("Service is deprecated - check validity period")
}
}

// Check status history
service.statusHistory.forEach { statusEntry ->
println("${statusEntry.status} from ${statusEntry.startDate}")
}

Trust Validation with TSL

Use trust lists for credential validation:

// Configure trust validator with ETSI trust lists
val trustValidator = TrustValidator {
etsiTrustLists {
// Load EU LOTL
lotlUrl = "https://ec.europa.eu/tools/lotl/eu-lotl.xml"

// Only trust qualified services
minimumStatus = TrustServiceStatus.QUALIFIED

// Cache settings
cacheEnabled = true
cacheDuration = Duration.ofHours(24)

// Refresh in background
backgroundRefresh = true
}
}

// Validate a certificate against trust lists
val result = trustValidator.validateTrust(
certificate = issuerCertificate,
purpose = TrustPurpose.CREDENTIAL_ISSUER
)

when (result) {
is TrustResult.Trusted -> {
// Certificate found in trust list
println("Issuer: ${result.trustServiceProvider}")
println("Service: ${result.trustService}")
println("Country: ${result.schemeTerritory}")
println("Status: ${result.serviceStatus}")
}
is TrustResult.NotTrusted -> {
println("Not found in trust lists")
}
}

Custom Trust Lists

Create custom trust lists following the ETSI format:

// Build a custom trust list
val customList = TrustedListBuilder()
.schemeOperatorName("My Organization")
.schemeTerritory("XX")
.tslVersionIdentifier(5)
.tslSequenceNumber(1)
.listIssueDateTime(Instant.now())
.nextUpdate(Instant.now().plus(Duration.ofDays(180)))
.trustServiceProvider {
name = "Internal Identity Provider"
tradeName = "Internal IDP"
electronicAddress = "https://idp.example.com"

service {
type = ServiceType.QUALIFIED_CERTIFICATE_FOR_ELECTRONIC_SIGNATURE
name = "Identity Credential Service"
status = TrustServiceStatus.GRANTED
startDate = Instant.now()

// Add service certificates
certificates = listOf(issuerCertificate)
}
}
.build()

// Register custom list with trust service
trustListService.registerCustomList(customList)

Trust List Caching

Configure caching for performance:

val trustListService = TrustListService {
// Enable caching
cache {
enabled = true
directory = context.cacheDir.resolve("trust-lists")
maxAge = Duration.ofHours(24)

// Keep expired cache as fallback
staleWhileRevalidate = true
}

// Background refresh
refresh {
enabled = true
interval = Duration.ofHours(12)
retryOnError = true
maxRetries = 3
}

// Network settings
http {
timeout = Duration.ofSeconds(30)
userAgent = "MyApp/1.0 IDK/0.13"
}
}

// Force refresh if needed
trustListService.refresh()

// Check cache status
val cacheStatus = trustListService.cacheStatus
println("Last update: ${cacheStatus.lastUpdate}")
println("Next refresh: ${cacheStatus.nextRefresh}")

Configuration

Configure trust list handling via properties:

# ETSI Trust Lists
trust.etsi.enabled=true
trust.etsi.lotl.url=https://ec.europa.eu/tools/lotl/eu-lotl.xml

# Caching
trust.etsi.cache.enabled=true
trust.etsi.cache.directory=${app.data.dir}/trust-lists
trust.etsi.cache.max-age-hours=24

# Background refresh
trust.etsi.refresh.enabled=true
trust.etsi.refresh.interval-hours=12

# Validation
trust.etsi.minimum-status=QUALIFIED
trust.etsi.verify-signatures=true

Best Practices

Cache trust lists aggressively. Trust lists are large and change infrequently. Use caching to improve performance and reduce network traffic.

Enable background refresh. Keep trust lists current by refreshing in the background, so validation is never blocked by network requests.

Verify trust list signatures. Trust lists are signed by the scheme operator. Always verify signatures to prevent tampering.

Handle offline scenarios. Use stale cache data when network is unavailable, but log warnings for monitoring.

Monitor trust list updates. Track when new versions are published and review changes that might affect your application.