Skip to main content

Managing Trust Infrastructure

This guide covers how to set up and manage trust infrastructure for a wallet deployment. Trust infrastructure is the foundation that enables issuers, verifiers, and wallets to establish and verify trust relationships.

Prerequisites

Before setting up trust infrastructure, ensure you understand:

Choosing a Trust Framework

Two primary trust frameworks are commonly used in credential ecosystems:

FrameworkBest ForComplexityStandards
ETSI TSL (X.509)EU/eIDAS compliance, government deploymentsMediumETSI TS 119 612
OpenID FederationDynamic ecosystems, OAuth/OIDC integrationHigherOpenID Federation 1.0

You can also use both frameworks simultaneously with Go-Trust acting as the unifying abstraction layer.


X.509 / ETSI Trust Status Lists

ETSI Trust Status Lists (TSLs) provide a standardized way to publish and consume trust information based on X.509 certificates. This approach is mandated by eIDAS and the EU Digital Identity framework.

Architecture Overview

Components Required

  1. Certificate Authority (CA) – Issues certificates to ecosystem participants
  2. Trust Status List (TSL) – XML document listing trusted services and their certificates
  3. TSL Signing Key – Private key used to sign the TSL (typically an HSM)
  4. Distribution Point – Web server or CDN to publish the TSL

Setting Up a Certificate Authority

For production, use an established CA or set up a proper PKI. For development/testing:

# Generate CA private key
openssl ecparam -genkey -name prime256v1 -out ca-key.pem

# Generate CA certificate
openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 365 \
-subj "/CN=My Trust Anchor CA/O=Example Org/C=SE"

# Issue a certificate for an issuer
openssl ecparam -genkey -name prime256v1 -out issuer-key.pem
openssl req -new -key issuer-key.pem -out issuer.csr \
-subj "/CN=issuer.example.com/O=Example Issuer/C=SE"
openssl x509 -req -in issuer.csr -CA ca-cert.pem -CAkey ca-key.pem \
-CAcreateserial -out issuer-cert.pem -days 365

Generating Trust Status Lists with tsl-tool

The g119612 project provides tsl-tool, a command-line tool for generating and processing ETSI TS 119 612 Trust Status Lists.

Installation

# Clone and build
git clone https://github.com/sirosfoundation/g119612.git
cd g119612
make build

# The binary is at ./tsl-tool

Creating a TSL Pipeline

Create a YAML pipeline configuration to generate your TSL:

# generate-tsl.yaml
- generate:
# TSL metadata
- scheme-name: "Example Trust Scheme"
- scheme-operator: "Example Organization"
- scheme-territory: "SE"
- tsl-type: "http://uri.etsi.org/TrstSvc/TrustedList/TSLType/EUgeneric"

# TSL signing
- signing-key: "/path/to/tsl-signing-key.pem"
- signing-cert: "/path/to/tsl-signing-cert.pem"

# Trust service providers
- providers:
- name: "Example Issuer"
trade-name: "Example Issuer Inc."
services:
- type: "http://uri.etsi.org/TrstSvc/Svctype/EDS/Q"
name: "Qualified Electronic Delivery Service"
status: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/granted"
certificate: "/path/to/issuer-cert.pem"
start-date: "2024-01-01T00:00:00Z"

- publish:
- /var/www/html/tsl
- my-trust-list.xml

Running the Pipeline

# Generate and publish the TSL
./tsl-tool --log-level info generate-tsl.yaml

# With debug output
./tsl-tool --log-level debug generate-tsl.yaml

Processing Existing TSLs

You can also use tsl-tool to fetch, transform, and republish existing TSLs:

# process-eu-tsl.yaml

# Configure HTTP client
- set-fetch-options:
- user-agent: TSL-Tool/1.0
- timeout: 60s

# Load the EU List of Trusted Lists
- load:
- https://ec.europa.eu/tools/lotl/eu-lotl.xml

# Follow references to member state TSLs
- select:
- reference-depth: 2

# Generate HTML documentation
- transform:
- embedded: tsl-to-html.xslt
- /var/www/html/trust-lists
- html

# Create an index page
- generate_index:
- /var/www/html/trust-lists
- "EU Trust Lists"

Publishing Your TSL

  1. Host on a reliable endpoint – Use HTTPS with a valid certificate
  2. Enable caching – TSLs change infrequently; set appropriate cache headers
  3. Consider a CDN – For high-availability deployments
  4. Set up monitoring – Alert on expiring TSLs or certificates
# Example nginx configuration
location /trust-list.xml {
root /var/www/html/tsl;
add_header Cache-Control "public, max-age=3600";
add_header Content-Type "application/xml";
}

Configuring Go-Trust to Use Your TSL

# go-trust config.yaml
registries:
etsi:
enabled: true
name: "ETSI-TSL"
description: "European Trust Status List"
cert_bundle: "/etc/go-trust/trusted-certs.pem"
# Or load from TSL URL (requires allow_network_access: true)
# tsl_urls:
# - "https://tsl.example.org/trust-list.xml"

Role-to-Service-Type Mapping

When vc and go-wallet-backend make trust evaluation requests, they use application-level roles like issuer and verifier. Go-Trust uses policies to map these roles to ETSI service types.

How Role Mapping Works

Standard Roles

The trust evaluation API uses these standard roles:

RoleDescriptionTypical ETSI Service Types
issuerCredential issuer (generic)QCert, CA/QC, EDS/Q
verifierRelying party/verifierEDS/Q, TSA/QTST
credential-issuerOpenID4VCI issuerQCert, CA/QC
credential-verifierOpenID4VP verifierEDS/Q
pid-providerPID (Person ID) providerQCert (with PID constraints)
wallet_providerWallet unit attestationCA/QC

Configuring Role-Based Policies

Define policies in Go-Trust to map roles to registry-specific constraints:

# go-trust config.yaml
policies:
# Default policy when no role matches
default_policy: credential-verifier

policies:
# Policy for credential issuers
credential-issuer:
description: "Validates credential issuers against qualified certificates"
etsi:
service_types:
- "http://uri.etsi.org/TrstSvc/Svctype/QCert"
- "http://uri.etsi.org/TrstSvc/Svctype/CA/QC"
service_statuses:
- "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/granted"
oidfed:
entity_types:
- "openid_credential_issuer"
required_trust_marks:
- "https://dc4eu.eu/tm/issuer"
did:
allowed_domains:
- "*.eudiw.dev"
- "*.example.com"
require_verifiable_history: true

# Policy for PID providers (stricter)
pid-provider:
description: "Validates PID providers with qualified certificate requirements"
etsi:
service_types:
- "http://uri.etsi.org/TrstSvc/Svctype/QCert"
countries:
- "DE"
- "FR"
- "SE"

# Policy for verifiers
credential-verifier:
description: "Validates relying parties"
etsi:
service_types:
- "http://uri.etsi.org/TrstSvc/Svctype/EDS/Q"
- "http://uri.etsi.org/TrstSvc/Svctype/TSA/QTST"
service_statuses:
- "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/granted"
oidfed:
entity_types:
- "openid_relying_party"
required_trust_marks:
- "https://dc4eu.eu/tm/verifier"
did:
allowed_domains:
- "*.eudiw.dev"
- "*.example.com"

# Policy for mDL issuers
mdl-issuer:
description: "Validates mDL/mDOC issuers via IACA"
mdociaca:
issuer_allowlist:
- "https://pid-issuer.eudiw.dev"
- "https://mdl-issuer.example.com"
require_iaca_endpoint: true
registries:
- "mdoc-iaca"

ETSI Service Type Reference

Common ETSI TS 119 612 service types:

URIDescription
http://uri.etsi.org/TrstSvc/Svctype/CA/QCCA issuing qualified certificates
http://uri.etsi.org/TrstSvc/Svctype/QCertQualified certificate service
http://uri.etsi.org/TrstSvc/Svctype/EDS/QQualified electronic delivery service
http://uri.etsi.org/TrstSvc/Svctype/TSA/QTSTQualified timestamp authority
http://uri.etsi.org/TrstSvc/Svctype/TSA/TSS-QCTimestamp for qualified certificates
http://uri.etsi.org/TrstSvc/Svctype/PSES/QQualified preservation service

Client-Side Usage

Applications don't need to know about ETSI service types – they just specify the role:

// In vc package (issuer verification)
req := trust.NewEvaluationRequest(issuerURL, trust.KeyTypeX5C, certChain)
req.Role = trust.RoleIssuer
decision, err := evaluator.Evaluate(ctx, req)

// In go-wallet-backend (verifier verification)
req := trust.NewEvaluationRequest(verifierURL, trust.KeyTypeX5C, certChain)
req.Role = trust.RoleVerifier
req.CredentialType = "PID" // May influence policy selection
decision, err := evaluator.Evaluate(ctx, req)

The Go-Trust server maps the role to the appropriate policy and ETSI constraints.


OpenID Federation

OpenID Federation provides dynamic, decentralized trust management where entities publish their own metadata and trust relationships are established through trust chains.

Architecture Overview

Key Concepts

TermDescription
Trust AnchorRoot of trust; publishes entity configuration and subordinate statements
IntermediateOptional organizational unit; can issue subordinate statements
Leaf EntityEnd entity (issuer, verifier, wallet) with metadata
Entity ConfigurationSelf-signed JWT describing an entity's metadata
Subordinate StatementJWT from superior entity attesting to a subordinate
Trust ChainChain of statements from leaf to trust anchor
Trust MarkAttestation that an entity meets certain criteria

Components Required

  1. Trust Anchor Service – Hosts federation endpoints and issues subordinate statements
  2. Entity Registration System – Manages onboarding of participants
  3. Key Management – Secure storage for signing keys
  4. Federation Endpoints – Well-known endpoints for metadata discovery

Running a Federation with Inmor

Inmor is an open-source OpenID Federation implementation that can be used to run trust anchor and intermediate entity services.

Installation

# Clone the repository
git clone https://github.com/SUNET/inmor.git
cd inmor

# Follow the installation instructions in the README
# Typically involves:
# - Setting up a Python environment
# - Configuring the database
# - Setting up signing keys

Basic Configuration

Inmor requires configuration for:

  1. Entity ID – The URL identifier for your trust anchor
  2. Signing Keys – Keys for signing entity configurations and subordinate statements
  3. Storage – Database for managing subordinates and trust marks
  4. Federation Policy – Rules for what metadata policies to apply

Federation Endpoints

A properly configured OpenID Federation entity exposes these endpoints:

EndpointDescription
/.well-known/openid-federationEntity Configuration (self-signed JWT)
/federation/fetchFetch subordinate statement by entity ID
/federation/listList all subordinate entities
/federation/resolveResolve complete trust chain
/federation/trust_mark_statusCheck trust mark validity

Registering Entities

To add an entity (issuer, verifier, wallet) to your federation:

  1. Entity provides their Entity Configuration – A self-signed JWT with their metadata
  2. Verify entity identity – Out-of-band verification of ownership
  3. Issue Subordinate Statement – Sign a statement attesting to the entity
  4. Entity publishes their configuration – At their /.well-known/openid-federation

Configuring Go-Trust for OpenID Federation

# go-trust config.yaml
registries:
- type: openid_federation
config:
trust_anchors:
- entity_id: "https://trust-anchor.example.org"
# Optional: pin the trust anchor's public key
jwks_uri: "https://trust-anchor.example.org/jwks.json"
cache_ttl: 5m
max_chain_length: 5
description: "Example Federation"

Combining Trust Frameworks

For production deployments, you often need to support multiple trust frameworks simultaneously:

# go-trust config.yaml with multiple frameworks
registries:
# ETSI TSL for EU compliance
- type: etsi_tsl
config:
trust_list_url: "https://ec.europa.eu/tools/lotl/eu-lotl.xml"
description: "EU Trust Lists"

# OpenID Federation for dynamic trust
- type: openid_federation
config:
trust_anchors:
- entity_id: "https://federation.example.org"
description: "Example Federation"

# Whitelist for known partners
- type: whitelist
config:
file: "/config/trusted-entities.json"
description: "Pre-approved entities"

# Query routing
query_routing:
resolution_strategy: first_match
routes:
- match:
resource_type: "x5c"
registries: ["etsi_tsl"]
- match:
resource_type: "jwk"
registries: ["openid_federation", "whitelist"]

Operational Considerations

Certificate/Key Lifecycle

AssetTypical ValidityRenewal Strategy
CA Root Certificate10-20 yearsPlan succession well in advance
Intermediate CA5-10 yearsRotate before expiry
TSL Signing Key2-5 yearsHSM-protected, ceremony for rotation
Entity Certificates1-2 yearsAutomated renewal (ACME)
Federation Signing Keys1-2 yearsKey rollover with overlap period

Monitoring and Alerting

  • Certificate expiry – Alert 30, 14, 7 days before expiry
  • TSL validity – Monitor nextUpdate field
  • Federation endpoint availability – Health checks on well-known endpoints
  • Trust chain resolution failures – Log and alert on resolution errors

High Availability

Disaster Recovery

  1. Backup signing keys – Secure, offline backup with ceremony for recovery
  2. TSL snapshots – Keep historical versions
  3. Federation database backups – Regular backups of subordinate registrations
  4. Documented recovery procedures – Test periodically

Next Steps