Skip to content

Commit 01438d8

Browse files
committed
Support normative ETSI trust lists
1 parent edb3f0f commit 01438d8

22 files changed

Lines changed: 1901 additions & 910 deletions

File tree

waltid-libraries/credentials/waltid-trust-registry/README.md

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,26 @@ Kotlin/JVM library for loading trust lists and resolving certificates, certifica
44

55
Supported inputs:
66

7-
- ETSI TS 119 612 Trust List XML
8-
- Provisional LoTE JSON and XML used by current EUDI pilots
9-
- LoTE JSON in a compact-JWS envelope
7+
- ETSI TS 119 612 Trust List and List of Trusted Lists XML
8+
- ETSI TS 119 602 V1.1.1 JSON, validated against the ETSI Annex A.1 schema
9+
- ETSI TS 119 602 V1.1.1 XML, validated against the ETSI Annex A.2.1 XSD
10+
- TS 119 602 JSON in a compact-JWS envelope
11+
12+
Other JSON/XML shapes are rejected.
13+
14+
## Standards status
15+
16+
| Area | Status |
17+
|---|---|
18+
| TS 119 602 Annex A.1 JSON syntax | ETSI JSON Schema validation and normalization implemented |
19+
| TS 119 602 Annex A.2.1 XML syntax | Offline ETSI XSD validation and normalization implemented |
20+
| TS 119 602 Annex A.2.2 / TS 119 612 XML | Ingestion implemented |
21+
| RFC 7515 compact JWS integrity | Implemented for embedded ECDSA payloads |
22+
| TS 119 602 profile rules, annexes D–I | Conformance test expansion required |
23+
| JAdES Baseline B / XAdES-B-B profile validation | Not complete; cryptographic signature validation alone is not a conformance claim |
24+
25+
The library must not be described as fully ETSI-conformant until the remaining profile rules and AdES validation are
26+
implemented and verified against an independent conformance suite.
1027

1128
## Security model
1229

@@ -96,13 +113,23 @@ check(result.assurance?.authenticityState == AuthenticityState.INTEGRITY_VERIFIE
96113

97114
For `AUTHENTICATED`, use `REQUIRE_AUTHENTICATED` and configure independently trusted TSL signer certificates.
98115

116+
The parser distinguishes a national trust list from the EU List of Trusted Lists (LoTL):
117+
118+
```kotlin
119+
check(result.format == TrustListFormat.ETSI_TS_119_612_TRUST_LIST_XML)
120+
```
121+
122+
For the EU LoTL, `result.format` is `ETSI_TS_119_612_LIST_OF_TRUST_LISTS_XML` and
123+
`result.pointersLoaded` reports the number of `OtherTSLPointer` entries. The library does not automatically fetch the
124+
member-state lists referenced by those pointers; register and load each required national list explicitly.
125+
99126
### Explicitly allow an unsigned list
100127

101128
Unsigned LoTE inputs require an explicit policy:
102129

103130
```kotlin
104131
val result = registry.loadSourceFromContent(
105-
sourceId = "pilot-lote",
132+
sourceId = "wallet-providers",
106133
content = loteJson,
107134
options = SourceLoadOptions(
108135
acceptancePolicy = SourceAcceptancePolicy.ALLOW_UNSIGNED
@@ -143,10 +170,15 @@ Failed refreshes do not replace the active source snapshot. `RefreshResult` prov
143170

144171
- Boolean `validateSignature` loading methods remain temporarily available but are deprecated. New integrations should use `SourceLoadOptions`.
145172
- Persisted sources created before the assurance model must be refreshed or migrated; missing assurance is treated as not admitted.
146-
- The LoTE JSON/XML shapes are provisional pilot formats, not claims of final ETSI schema conformance.
147173
- Compact JWS support validates embedded payloads and pinned X.509 signers; it is not full JAdES support.
148174
- `InMemoryTrustStore` is thread-safe but not persistent. Production deployments should provide a persistent `TrustStore` implementation.
149175

176+
Useful public test sources:
177+
178+
- Austria TSL: `https://www.signatur.rtr.at/vertrauensliste.xml`
179+
- Italy TSL: `https://eidas.agid.gov.it/TL/TSL-IT.xml`
180+
- EU LoTL: `https://ec.europa.eu/tools/lotl/eu-lotl.xml`
181+
150182
## Tests
151183

152184
```bash
@@ -155,3 +187,10 @@ Failed refreshes do not replace the active source snapshot. `RefreshResult` prov
155187
```
156188

157189
Network tests are disabled by default. Enable them explicitly with `RUN_NETWORK_TESTS=true`.
190+
191+
Normative references:
192+
193+
- ETSI TS 119 602 V1.1.1: <https://www.etsi.org/deliver/etsi_ts/119600_119699/119602/01.01.01_60/ts_119602v010101p.pdf>
194+
- ETSI schemas, pinned in the implementation to commit `e84f427f0cde99513b574ef4b5a155ac4a38eab6`:
195+
<https://forge.etsi.org/rep/esi/x19_60201_lists_of_trusted_entities>
196+
- ETSI TS 119 612 V2.4.1: <https://www.etsi.org/deliver/etsi_ts/119600_119699/119612/02.04.01_60/ts_119612v020401p.pdf>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
The embedded ETSI TS 119 602 JSON schema is derived from:
2+
https://forge.etsi.org/rep/esi/x19_60201_lists_of_trusted_entities
3+
commit e84f427f0cde99513b574ef4b5a155ac4a38eab6
4+
5+
Copyright 2025 ETSI
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
1. Redistributions of source code must retain the above copyright notice,
10+
this list of conditions and the following disclaimer.
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
3. Neither the name of the copyright holder nor the names of its contributors
15+
may be used to endorse or promote products derived from this software without
16+
specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27+
OF THE POSSIBILITY OF SUCH DAMAGE.

waltid-libraries/credentials/waltid-trust-registry/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ kotlin {
1313
implementation(identityLibs.kotlinx.serialization.json)
1414
implementation(identityLibs.kotlinx.datetime)
1515
implementation(identityLibs.kotlinx.coroutines.core)
16+
implementation(identityLibs.optimumcode.jsonschemavalidator)
1617

1718
// HTTP fetching (KMP Ktor client core)
1819
implementation(identityLibs.bundles.waltid.ktor.client)

waltid-libraries/credentials/waltid-trust-registry/src/commonMain/kotlin/id/walt/trust/model/TrustModel.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@ import kotlin.time.Instant
88
// ---------------------------------------------------------------------------
99

1010
@Serializable
11-
enum class SourceFamily { TSL, LOTE, PILOT }
11+
enum class SourceFamily {
12+
TSL,
13+
LOTE
14+
}
15+
16+
/** Concrete syntax and role of an ingested trust-list artifact. */
17+
@Serializable
18+
enum class TrustListFormat {
19+
ETSI_TS_119_612_TRUST_LIST_XML,
20+
ETSI_TS_119_612_LIST_OF_TRUST_LISTS_XML,
21+
ETSI_TS_119_602_JSON,
22+
ETSI_TS_119_602_XML,
23+
UNKNOWN
24+
}
1225

1326
// ---------------------------------------------------------------------------
1427
// Source assurance / freshness state
@@ -78,6 +91,7 @@ data class TrustSource(
7891
val sourceId: String,
7992
val sourceFamily: SourceFamily,
8093
val displayName: String,
94+
val format: TrustListFormat = TrustListFormat.UNKNOWN,
8195
val sourceUrl: String? = null,
8296
val territory: String? = null,
8397
val issueDate: Instant? = null,
@@ -211,6 +225,7 @@ data class TrustSourceHealth(
211225
val sourceId: String,
212226
val displayName: String,
213227
val sourceFamily: SourceFamily,
228+
val format: TrustListFormat = TrustListFormat.UNKNOWN,
214229
val freshnessState: FreshnessState,
215230
val assurance: SourceAssurance,
216231
val nextUpdate: Instant? = null,
@@ -229,6 +244,7 @@ data class RefreshResult(
229244
val entitiesLoaded: Int = 0,
230245
val servicesLoaded: Int = 0,
231246
val identitiesLoaded: Int = 0,
247+
val pointersLoaded: Int = 0,
232248
val error: String? = null,
233249
val errorCode: SourceLoadErrorCode? = null,
234250
val assurance: SourceAssurance? = null

waltid-libraries/credentials/waltid-trust-registry/src/commonMain/kotlin/id/walt/trust/parser/lote/EtsiLoteJsonSchema.kt

Lines changed: 27 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)