@owf/eudi-tl 0.4.0-alpha-20260901082001

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,785 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let _owf_identity_common = require("@owf/identity-common");
25
+ let _peculiar_x509 = require("@peculiar/x509");
26
+ let _xmldom_xmldom = require("@xmldom/xmldom");
27
+ let zod = require("zod");
28
+ let xadesjs = require("xadesjs");
29
+ xadesjs = __toESM(xadesjs);
30
+ let xpath = require("xpath");
31
+ xpath = __toESM(xpath);
32
+ //#region src/constants.ts
33
+ /**
34
+ * Well-known ETSI TS 119 612 URIs.
35
+ *
36
+ * These are the standard values used by eIDAS national trusted lists. Profiled
37
+ * lists may use their own profile-specific URIs (validated via a caller-supplied
38
+ * {@link ProfileRule}); this library's parser is agnostic to both.
39
+ */
40
+ /** Standard `TSLType` values (TS 119 612 clause 5.3.3). */
41
+ const TSLType = {
42
+ EUgeneric: "http://uri.etsi.org/TrstSvc/TrustedList/TSLType/EUgeneric",
43
+ EUlistofthelists: "http://uri.etsi.org/TrstSvc/TrustedList/TSLType/EUlistofthelists"
44
+ };
45
+ /** Standard `ServiceStatus` values (TS 119 612 clause 5.5.4). */
46
+ const ServiceStatus = {
47
+ Granted: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/granted",
48
+ Withdrawn: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/withdrawn",
49
+ UnderSupervision: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/undersupervision",
50
+ SupervisionCeased: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/supervisionceased",
51
+ SupervisionInCessation: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/supervisionincessation",
52
+ Accredited: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/accredited",
53
+ AccreditationCeased: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/accreditationceased",
54
+ AccreditationRevoked: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/accreditationrevoked",
55
+ SetByNationalLaw: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/setbynationallaw",
56
+ RecognisedAtNationalLevel: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/recognisedatnationallevel",
57
+ DeprecatedAtNationalLevel: "http://uri.etsi.org/TrstSvc/TrustedList/Svcstatus/deprecatedatnationallevel"
58
+ };
59
+ /**
60
+ * Service statuses that denote a currently active / trustworthy service under
61
+ * TS 119 612. Use as the `serviceStatus` filter when extracting trust anchors
62
+ * from a standard eIDAS list; withdrawn/ceased services are excluded.
63
+ */
64
+ const ACTIVE_SERVICE_STATUSES = [
65
+ ServiceStatus.Granted,
66
+ ServiceStatus.UnderSupervision,
67
+ ServiceStatus.Accredited,
68
+ ServiceStatus.SetByNationalLaw,
69
+ ServiceStatus.RecognisedAtNationalLevel
70
+ ];
71
+ /** Common standard `ServiceTypeIdentifier` values (TS 119 612 Annex D). */
72
+ const ServiceType = {
73
+ /** Qualified certificate CA. */
74
+ CA_QC: "http://uri.etsi.org/TrstSvc/Svctype/CA/QC",
75
+ /** Public key certificate CA. */
76
+ CA_PKC: "http://uri.etsi.org/TrstSvc/Svctype/CA/PKC",
77
+ /** Qualified timestamping authority. */
78
+ TSA_QTST: "http://uri.etsi.org/TrstSvc/Svctype/TSA/QTST",
79
+ /** Qualified electronic delivery service. */
80
+ EDS_Q: "http://uri.etsi.org/TrstSvc/Svctype/EDS/Q",
81
+ /** Qualified registered electronic mail delivery service. */
82
+ EDS_REM_Q: "http://uri.etsi.org/TrstSvc/Svctype/EDS/REM/Q",
83
+ /** Qualified preservation service for electronic signatures/seals. */
84
+ PSES_Q: "http://uri.etsi.org/TrstSvc/Svctype/PSES/Q",
85
+ /** Qualified validation service for qualified electronic signatures. */
86
+ QESValidation_Q: "http://uri.etsi.org/TrstSvc/Svctype/QESValidation/Q",
87
+ /** OCSP responder for qualified certificates. */
88
+ OCSP_QC: "http://uri.etsi.org/TrstSvc/Svctype/Certstatus/OCSP/QC"
89
+ };
90
+ //#endregion
91
+ //#region src/eu-lotl-anchors.ts
92
+ /**
93
+ * The signing certificates published by the LOTL identified in
94
+ * {@link EU_LOTL_ANCHORS_PROVENANCE}. Any of them may sign a future issue of the
95
+ * list, so the whole published set is pinned, not just the current signer.
96
+ */
97
+ const EU_LOTL_SIGNING_CERTIFICATES = [
98
+ {
99
+ certificate: "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",
100
+ subject: "C=LU, OU=Certificate Profile - Qualified Certificate - Organization, OU=Directorate-General for Digital Services, 2.5.4.97=LEIXG-254900ZNYA1FLUQ9U393, O=EUROPEAN COMMISSION, E=EU-TRUST@ec.europa.eu, CN=EUROPEAN COMMISSION",
101
+ fingerprintSha256: "236103f03a8031ae8f47f9059bf8de38564cdbfebedde4a597d50f8980aa653b",
102
+ notAfter: "2029-12-17T14:31:54.000Z"
103
+ },
104
+ {
105
+ certificate: "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",
106
+ subject: "C=GR, OU=Certificate Profile - Qualified Certificate - Member, 2.5.4.97=LEIXG-254900ZNYA1FLUQ9U393, O=EUROPEAN COMMISSION, OU=Entitlement - EC STATUTORY STAFF, E=apostolos.apladas@ec.europa.eu, SN=APLADAS, G=APOSTOLOS, OU=RemoteQSCDManagement, CN=APOSTOLOS APLADAS",
107
+ fingerprintSha256: "b63d416744e7098bf9ec2caa596a93bc2468e37f8284ba65ecc061711bcbaa18",
108
+ notAfter: "2027-04-26T12:49:22.000Z"
109
+ },
110
+ {
111
+ certificate: "MIIIBDCCBeygAwIBAgIUcMz/PU9hyZj1+vaAghkzK31AkUswDQYJKoZIhvcNAQENBQAwXzELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmljYWRvcmEgRGlnaXRhbDEkMCIGA1UEAwwbRElHSVRBTFNJR04gUVVBTElGSUVEIENBIEcxMB4XDTI1MTEyNDA5NTY0MVoXDTI5MTEyMzA5NTY0MVowggFWMQswCQYDVQQGEwJHUjE9MDsGA1UECww0Q2VydGlmaWNhdGUgUHJvZmlsZSAtIFF1YWxpZmllZCBDZXJ0aWZpY2F0ZSAtIE1lbWJlcjEjMCEGA1UEYQwaTEVJWEctMjU0OTAwWk5ZQTFGTFVROVUzOTMxHDAaBgNVBAoME0VVUk9QRUFOIENPTU1JU1NJT04xKTAnBgNVBAsMIEVudGl0bGVtZW50IC0gRUMgU1RBVFVUT1JZIFNUQUZGMTEwLwYJKoZIhvcNAQkBFiJJb2FubmEuS0FMT0dFUk9QT1VMT1VAZWMuZXVyb3BhLmV1MRcwFQYDVQQEDA5LQUxPR0VST1BPVUxPVTEPMA0GA1UEKgwGSU9BTk5BMR0wGwYDVQQLDBRSZW1vdGVRU0NETWFuYWdlbWVudDEeMBwGA1UEAwwVSU9BTk5BIEtBTE9HRVJPUE9VTE9VMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAswjmtemrpGlPsoCM1tVfVICYiyK0eIodby6nK00KfkS8K9gEou+OZjJ5B85VmEC7u889RAG1DUr6k+7Setz9E/qYdFhz/3GJw10XsEuRcwdzafvKM9DrXFFkGYRqKSkJ67/sKq1JKE7bCkbMZ/B8SDRUJ2veSoRS/oC5GhufarAZOxXUwrzb723BTwQGkar/G0Y7co1eVQXX6hGy4mnPF36APvG941p/IuoMM5Ib610h/I1zB5DFIgAVEi0HnlCoLfQ6oqJcv01WfGKEIhppoephuhSE7EqQ0JLIuf8zdunyY/Mmvz4it2jFV/QQf1R87StpL7AicC5BSCWfiXyD7wIDAQABo4ICvTCCArkwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRzSfFAHBQEfJoSf/ovzVxnIxjpFDCBhgYIKwYBBQUHAQEEejB4MEYGCCsGAQUFBzAChjpodHRwczovL3FjYS1nMS5kaWdpdGFsc2lnbi5wdC9ESUdJVEFMU0lHTlFVQUxJRklFRENBRzEucDdiMC4GCCsGAQUFBzABhiJodHRwczovL3FjYS1nMS5kaWdpdGFsc2lnbi5wdC9vY3NwMC0GA1UdEQQmMCSBIklvYW5uYS5LQUxPR0VST1BPVUxPVUBlYy5ldXJvcGEuZXUwXwYDVR0gBFgwVjA3BgsrBgEEAYHHfAQBATAoMCYGCCsGAQUFBwIBFhpodHRwczovL3BraS5kaWdpdGFsc2lnbi5wdDAQBg4rBgEEAYHHfAQCAQEBBDAJBgcEAIvsQAECMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDBLBgNVHR8ERDBCMECgPqA8hjpodHRwczovL3FjYS1nMS5kaWdpdGFsc2lnbi5wdC9ESUdJVEFMU0lHTlFVQUxJRklFRENBRzEuY3JsMB0GA1UdDgQWBBQOe+jKZg/EC79WvQ/Ven54zd1YxDAOBgNVHQ8BAf8EBAMCBkAwgdMGCCsGAQUFBwEDBIHGMIHDMAgGBgQAjkYBATAIBgYEAI5GAQQwEwYGBACORgEGMAkGBwQAjkYBBgEwagYGBACORgEFMGAwLhYoaHR0cHM6Ly9xY2EtZzEuZGlnaXRhbHNpZ24ucHQvUERTX3B0LnBkZhMCcHQwLhYoaHR0cHM6Ly9xY2EtZzEuZGlnaXRhbHNpZ24ucHQvUERTX2VuLnBkZhMCZW4wFQYIKwYBBQUHCwIwCQYHBACL7EkBATAVBggrBgEFBQcLAjAJBgcEAIvsSQECMA0GCSqGSIb3DQEBDQUAA4ICAQBXav52/+LXYZAgA0MjuEI/+NacJC9E9VRIkIIvrLzAHcj2KQ2GLR1fL8C2UIJ6u2+LwG2mIyyK2F16erDoOWKDV40vxgGEfSwgin6GUhHmzuRDPBQhUW4C7btUFMoAr05UT+v03d9RrnlA5bpKSlKaf2J3EGAfGR1DvvFJ+ZCFaVo+8rtcLpySS3f8ZPCqz3axaO3KeyK4LuJbdZqGArKIF0vNKGR94rr7Pq7OIIHJBuOW9LGQG0r5e8kb/KRLZBsPlHpgPVZc8M3EimqYmIg6hgPf0k+Mxhw5/IC4rikFsMTNa43yBeGrk2pvM8cIZoenmQMgf/1L0+A9Pwol+7CUQfe4Bpj0fr1Acnx/4oPnAKmMDKvXnx91fMW2b7Uen2y11TcijxYuXftq03bx8w/ms/giXYLGciDcwCF7XCXNnGuATW/GxPvOxOwu56ZDrm/oG3zfa4l/tF/S5swoFrzmTDIIM05UzHDUuQAln103BGfEYKo7vw4bNfouHfS28qGWbotUSNzHfOEqeC4LrdN7JmE8q0hZRXLFOIsPtG/S0rEkuoNl3znZPmk8oAy/xa1+3XnH1nJCVmTK0XQYaTPinAAEnDbTqUjD97zmUFEd+ecOctica4DFhQoHtUDYUOzKEKfKHVEG0ApI3dpHzcLiuLXIQl0DBvfy3wspy6HL3A==",
112
+ subject: "C=GR, OU=Certificate Profile - Qualified Certificate - Member, 2.5.4.97=LEIXG-254900ZNYA1FLUQ9U393, O=EUROPEAN COMMISSION, OU=Entitlement - EC STATUTORY STAFF, E=Ioanna.KALOGEROPOULOU@ec.europa.eu, SN=KALOGEROPOULOU, G=IOANNA, OU=RemoteQSCDManagement, CN=IOANNA KALOGEROPOULOU",
113
+ fingerprintSha256: "c0641c4f7d56c431b1c924742db7fce9c1eef7d7fd212113a2768486b3abcdc5",
114
+ notAfter: "2029-11-23T09:56:41.000Z"
115
+ },
116
+ {
117
+ certificate: "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",
118
+ subject: "C=BE, CN=Patrick Kremer (Signature), SN=Kremer, G=Patrick Jean, 2.5.4.5=72020329970",
119
+ fingerprintSha256: "d2064fdd70f6982dcc516b86d9d5c56aea939417c624b2e478c0b29de54f8474",
120
+ notAfter: "2028-05-30T23:59:59.000Z"
121
+ },
122
+ {
123
+ certificate: "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",
124
+ subject: "C=ES, OU=Certificate Profile - Qualified Certificate - Member, 2.5.4.97=LEIXG-254900ZNYA1FLUQ9U393, O=EUROPEAN COMMISSION, OU=Entitlement - EC STATUTORY STAFF, E=vicente.andreu-navarro@ec.europa.eu, SN=ANDREU NAVARRO, G=VICENTE, OU=RemoteQSCDManagement, CN=VICENTE ANDREU NAVARRO",
125
+ fingerprintSha256: "df7e29360c34b2b8d6d5f40325c1d4d12c9922cecd33b7407674a74b2b3ca1e5",
126
+ notAfter: "2027-05-06T12:45:16.000Z"
127
+ },
128
+ {
129
+ certificate: "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",
130
+ subject: "C=LU, OU=Certificate Profile - Qualified Certificate - Organization, OU=Directorate-General for Digital Services (DIGIT), 2.5.4.97=LEIXG-254900ZNYA1FLUQ9U393, O=EUROPEAN COMMISSION, E=digit-dmo@ec.europa.eu, CN=EUROPEAN COMMISSION",
131
+ fingerprintSha256: "e0a620fbb6747362bb933ac44169d676a553444716cf5f31605f12a22b8396b1",
132
+ notAfter: "2027-11-17T10:11:46.000Z"
133
+ }
134
+ ];
135
+ /** Where this set came from, so the pin can be audited without re-running the script. */
136
+ const EU_LOTL_ANCHORS_PROVENANCE = {
137
+ /** The list the certificates were read from. */
138
+ source: "https://ec.europa.eu/tools/lotl/eu-lotl.xml",
139
+ /** The Official Journal act the LOTL itself references for its signers. */
140
+ officialJournal: "https://eur-lex.europa.eu/eli/C/2026/1944/oj",
141
+ /** `TSLSequenceNumber` of that list. */
142
+ tslSequenceNumber: 390,
143
+ /** `ListIssueDateTime` of that list. */
144
+ listIssueDateTime: "2026-08-03T13:16:38Z",
145
+ /** Earliest expiry in the set: refresh before this date. */
146
+ earliestNotAfter: "2027-04-26T12:49:22.000Z"
147
+ };
148
+ //#endregion
149
+ //#region src/trusted-list-exception.ts
150
+ /**
151
+ * Base exception for all trusted-list processing failures.
152
+ */
153
+ var TrustedListException = class extends Error {
154
+ constructor(message, options) {
155
+ super(message);
156
+ this.name = "TrustedListException";
157
+ this.cause = options?.cause;
158
+ }
159
+ };
160
+ /**
161
+ * The XML could not be parsed as an ETSI TS 119 612 `TrustServiceStatusList`.
162
+ */
163
+ var TrustedListParseException = class extends TrustedListException {
164
+ constructor(message, options) {
165
+ super(message, options);
166
+ this.name = "TrustedListParseException";
167
+ }
168
+ };
169
+ /**
170
+ * The trusted list's own XAdES/XMLDSig signature is missing, invalid, or does
171
+ * not match a configured trust anchor. Callers MUST treat this as fail-closed:
172
+ * a trusted list whose authenticity cannot be established must not be used to
173
+ * trust credentials.
174
+ */
175
+ var TrustedListSignatureException = class extends TrustedListException {
176
+ constructor(message, options) {
177
+ super(message, options);
178
+ this.name = "TrustedListSignatureException";
179
+ }
180
+ };
181
+ //#endregion
182
+ //#region src/types.ts
183
+ /**
184
+ * A service's digital identity (TS 119 612 `ServiceDigitalIdentity`): the
185
+ * `DigitalId` children (X509Certificate, X509SubjectName, X509SKI) that describe
186
+ * one entity are merged here. A standard list may identify a service by subject
187
+ * name and/or key identifier without embedding the full certificate.
188
+ */
189
+ const DigitalIdentitySchema = zod.z.object({
190
+ /** base64-encoded DER of the certificate, when embedded (`X509Certificate`). */
191
+ certificate: zod.z.string().optional(),
192
+ /** `X509SubjectName`, when present. */
193
+ subjectName: zod.z.string().optional(),
194
+ /**
195
+ * Lowercase-hex SubjectKeyIdentifier — derived from the certificate when one
196
+ * is embedded, otherwise from the `X509SKI` element. This is the value a
197
+ * verifier sends to a wallet as an `aki` trusted authority (HAIP).
198
+ */
199
+ subjectKeyIdentifier: zod.z.string().optional()
200
+ });
201
+ /** A past status entry for a service (`ServiceHistoryInstance`). */
202
+ const ServiceHistoryInstanceSchema = zod.z.object({
203
+ serviceTypeIdentifier: zod.z.string().optional(),
204
+ serviceStatus: zod.z.string(),
205
+ statusStartingTime: zod.z.string().optional()
206
+ });
207
+ /**
208
+ * A trust service (TSPService) entry: its type, status, digital identities,
209
+ * qualifiers, and status history.
210
+ */
211
+ const TrustedListServiceSchema = zod.z.object({
212
+ /** `ServiceTypeIdentifier` URI. */
213
+ serviceTypeIdentifier: zod.z.string(),
214
+ /** Current `ServiceStatus` URI. */
215
+ serviceStatus: zod.z.string(),
216
+ /** Human-readable service name, if present. */
217
+ serviceName: zod.z.string().optional(),
218
+ /** One entry per `ServiceDigitalIdentity`. */
219
+ digitalIdentities: zod.z.array(DigitalIdentitySchema),
220
+ /** Qualifier URIs from `Qualifications/QualificationElement/Qualifiers`. */
221
+ qualifiers: zod.z.array(zod.z.string()).optional(),
222
+ /** Prior status entries from `ServiceHistory`. */
223
+ history: zod.z.array(ServiceHistoryInstanceSchema).optional()
224
+ });
225
+ /** A Trust Service Provider (TSP) and the services it operates. */
226
+ const TrustServiceProviderSchema = zod.z.object({
227
+ name: zod.z.string().optional(),
228
+ services: zod.z.array(TrustedListServiceSchema)
229
+ });
230
+ /** A pointer to another trusted list (`OtherTSLPointer`), e.g. the EU LOTL. */
231
+ const TrustedListPointerSchema = zod.z.object({
232
+ /** `TSLLocation` URL. */
233
+ location: zod.z.string(),
234
+ /** Pointed-to list `TSLType`, when advertised. */
235
+ tslType: zod.z.string().optional(),
236
+ /** `SchemeTerritory` (country code), when advertised. */
237
+ schemeTerritory: zod.z.string().optional(),
238
+ /**
239
+ * The pointer's `ServiceDigitalIdentities`: the certificates with which the
240
+ * pointed-to list is signed. This is how a list distributes the trust anchors
241
+ * of the lists it points to — the EU LOTL carries, for every national list,
242
+ * the certificate(s) of its scheme operator, so a verifier that trusts the
243
+ * LOTL does not need to pin each national list separately.
244
+ */
245
+ digitalIdentities: zod.z.array(DigitalIdentitySchema).default([])
246
+ });
247
+ /** A parsed ETSI TS 119 612 Trusted List (`TrustServiceStatusList`). */
248
+ const TrustedListSchema = zod.z.object({
249
+ /** `TSLType` URI. */
250
+ tslType: zod.z.string().optional(),
251
+ /** `SchemeOperatorName` (English name when available). */
252
+ schemeOperatorName: zod.z.string().optional(),
253
+ /** `TSLSequenceNumber`. */
254
+ sequenceNumber: zod.z.number().optional(),
255
+ /** `ListIssueDateTime` (ISO 8601). */
256
+ listIssueDateTime: zod.z.string().optional(),
257
+ /** `NextUpdate` (ISO 8601), when present. */
258
+ nextUpdate: zod.z.string().optional(),
259
+ providers: zod.z.array(TrustServiceProviderSchema),
260
+ /** `PointersToOtherTSL` entries (e.g. the EU LOTL). Not followed by v1. */
261
+ pointersToOtherLists: zod.z.array(TrustedListPointerSchema).optional()
262
+ });
263
+ /**
264
+ * A flattened trust anchor: one digital identity with the service context it was
265
+ * published under. The normalized unit both certificate-chain validation and AKI
266
+ * emission consume — the ETSI TS 119 612 counterpart of a `@owf/eudi-lote`
267
+ * TrustedEntity service certificate.
268
+ */
269
+ const TrustAnchorSchema = zod.z.object({
270
+ /** base64 DER certificate, when the identity embeds one. */
271
+ certificate: zod.z.string().optional(),
272
+ subjectName: zod.z.string().optional(),
273
+ subjectKeyIdentifier: zod.z.string().optional(),
274
+ serviceTypeIdentifier: zod.z.string(),
275
+ serviceStatus: zod.z.string(),
276
+ providerName: zod.z.string().optional()
277
+ });
278
+ //#endregion
279
+ //#region src/validate.ts
280
+ function fromZodError(error) {
281
+ return error.issues.map((issue) => ({
282
+ path: issue.path.map((p) => String(p)).join("."),
283
+ message: issue.message
284
+ }));
285
+ }
286
+ /**
287
+ * Structurally validate an object against the ETSI TS 119 612 trusted-list
288
+ * schema (the same zod-based approach `@owf/eudi-lote` uses for TS 119 602).
289
+ * For XML input, parse it first with `parseTrustedList` (XML → object), then
290
+ * validate the object here.
291
+ */
292
+ function validateTrustedList(value) {
293
+ const result = TrustedListSchema.safeParse(value);
294
+ return result.success ? {
295
+ valid: true,
296
+ errors: []
297
+ } : {
298
+ valid: false,
299
+ errors: fromZodError(result.error)
300
+ };
301
+ }
302
+ /**
303
+ * Structurally validate and return the typed trusted list, throwing
304
+ * {@link TrustedListParseException} when it does not conform to the schema.
305
+ */
306
+ function assertValidTrustedList(value) {
307
+ const result = TrustedListSchema.safeParse(value);
308
+ if (!result.success) throw new TrustedListParseException(`Invalid trusted list: ${fromZodError(result.error).map((e) => `${e.path}: ${e.message}`).join("; ")}`);
309
+ return result.data;
310
+ }
311
+ /**
312
+ * Compare ETSI URIs scheme-insensitively: deployed lists have published the
313
+ * same URI over both `http` and `https`. Internal helper, not part of the
314
+ * package's public API.
315
+ */
316
+ const stripScheme = (uri) => (uri ?? "").replace(/^https?:\/\//, "");
317
+ function profileErrors(trustedList, rule) {
318
+ const label = rule.name ?? "profile";
319
+ const errors = [];
320
+ if (stripScheme(trustedList.tslType) !== stripScheme(rule.tslType)) errors.push({
321
+ path: "tslType",
322
+ message: `[${label}] expected TSLType ${rule.tslType}, got ${trustedList.tslType ?? "none"}`
323
+ });
324
+ const allowedTypes = new Set(rule.serviceTypes.map(stripScheme));
325
+ const allowedStatuses = new Set(rule.serviceStatuses.map(stripScheme));
326
+ trustedList.providers.forEach((provider, pi) => {
327
+ provider.services.forEach((service, si) => {
328
+ if (!allowedTypes.has(stripScheme(service.serviceTypeIdentifier))) errors.push({
329
+ path: `providers.${pi}.services.${si}.serviceTypeIdentifier`,
330
+ message: `[${label}] unexpected service type ${service.serviceTypeIdentifier}`
331
+ });
332
+ if (!allowedStatuses.has(stripScheme(service.serviceStatus))) errors.push({
333
+ path: `providers.${pi}.services.${si}.serviceStatus`,
334
+ message: `[${label}] unexpected service status ${service.serviceStatus}`
335
+ });
336
+ });
337
+ });
338
+ return errors;
339
+ }
340
+ /**
341
+ * Validate that a trusted list conforms to one (or any, given several) of the
342
+ * supplied profile rules — structural schema first, then profile-specific
343
+ * constraints. Mirrors `@owf/eudi-lote`'s profile validation.
344
+ */
345
+ function validateTrustedListProfile(value, rule) {
346
+ const structural = validateTrustedList(value);
347
+ if (!structural.valid) return structural;
348
+ const trustedList = value;
349
+ const perRule = (Array.isArray(rule) ? rule : [rule]).map((r) => profileErrors(trustedList, r));
350
+ if (perRule.some((errors) => errors.length === 0)) return {
351
+ valid: true,
352
+ errors: []
353
+ };
354
+ return {
355
+ valid: false,
356
+ errors: perRule.flat()
357
+ };
358
+ }
359
+ //#endregion
360
+ //#region src/parse.ts
361
+ const TSL_NS = "http://uri.etsi.org/02231/v2#";
362
+ const SIE_NS = "http://uri.etsi.org/TrstSvc/SvcInfoExt/eSigDir-1999-93-EC-TrustedList/#";
363
+ function descendants(el, name, ns = TSL_NS) {
364
+ return Array.from(el.getElementsByTagNameNS(ns, name));
365
+ }
366
+ function firstDescendant(el, name, ns = TSL_NS) {
367
+ return descendants(el, name, ns)[0];
368
+ }
369
+ function textOf(el) {
370
+ const t = el?.textContent?.trim();
371
+ return t ? t : void 0;
372
+ }
373
+ /**
374
+ * Localized `Name`: prefer the English entry, else the first, searched only
375
+ * among the direct `Name` children of the given parent.
376
+ */
377
+ function localizedName(parent) {
378
+ if (!parent) return void 0;
379
+ const names = Array.from(parent.childNodes).filter((n) => n.namespaceURI === TSL_NS && n.localName === "Name");
380
+ if (names.length === 0) return void 0;
381
+ return textOf(names.find((n) => n.getAttribute("xml:lang") === "en") ?? names[0]);
382
+ }
383
+ /** Lowercase-hex SubjectKeyIdentifier from a certificate, best-effort. */
384
+ function skiFromCertificate(certBase64) {
385
+ try {
386
+ const ext = new _peculiar_x509.X509Certificate(certBase64).getExtension(_peculiar_x509.SubjectKeyIdentifierExtension);
387
+ if (ext?.keyId) return ext.keyId.toLowerCase();
388
+ } catch {}
389
+ }
390
+ /**
391
+ * One {@link DigitalIdentity} per `ServiceDigitalIdentity`, merging its
392
+ * `DigitalId` children (X509Certificate / X509SubjectName / X509SKI) — a
393
+ * standard list may identify a service without embedding the full certificate.
394
+ */
395
+ function parseDigitalIdentities(container) {
396
+ const identities = [];
397
+ for (const sdi of descendants(container, "ServiceDigitalIdentity")) {
398
+ let certificate;
399
+ let subjectName;
400
+ let x509SkiHex;
401
+ for (const digitalId of descendants(sdi, "DigitalId")) {
402
+ certificate ??= textOf(firstDescendant(digitalId, "X509Certificate"))?.replace(/\s/g, "");
403
+ subjectName ??= textOf(firstDescendant(digitalId, "X509SubjectName"));
404
+ const ski = textOf(firstDescendant(digitalId, "X509SKI"));
405
+ if (ski && !x509SkiHex) x509SkiHex = (0, _owf_identity_common.hexEncode)(_owf_identity_common.base64.decode(ski.replace(/\s/g, "")));
406
+ }
407
+ if (!certificate && !subjectName && !x509SkiHex) continue;
408
+ identities.push({
409
+ certificate,
410
+ subjectName,
411
+ subjectKeyIdentifier: certificate ? skiFromCertificate(certificate) ?? x509SkiHex : x509SkiHex
412
+ });
413
+ }
414
+ return identities;
415
+ }
416
+ function parseQualifiers(serviceInfo) {
417
+ const uris = descendants(serviceInfo, "Qualifier", SIE_NS).map((q) => q.getAttribute("uri") ?? "").filter((u) => u.length > 0);
418
+ return uris.length > 0 ? uris : void 0;
419
+ }
420
+ function parseHistory(service) {
421
+ const history = [];
422
+ for (const instance of descendants(service, "ServiceHistoryInstance")) {
423
+ const serviceStatus = textOf(firstDescendant(instance, "ServiceStatus"));
424
+ if (!serviceStatus) continue;
425
+ history.push({
426
+ serviceTypeIdentifier: textOf(firstDescendant(instance, "ServiceTypeIdentifier")),
427
+ serviceStatus,
428
+ statusStartingTime: textOf(firstDescendant(instance, "StatusStartingTime"))
429
+ });
430
+ }
431
+ return history.length > 0 ? history : void 0;
432
+ }
433
+ function parsePointers(schemeInfo) {
434
+ const pointers = [];
435
+ for (const pointer of descendants(schemeInfo, "OtherTSLPointer")) {
436
+ const location = textOf(firstDescendant(pointer, "TSLLocation"));
437
+ if (!location) continue;
438
+ pointers.push({
439
+ location,
440
+ tslType: textOf(firstDescendant(pointer, "TSLType")),
441
+ schemeTerritory: textOf(firstDescendant(pointer, "SchemeTerritory")),
442
+ digitalIdentities: parseDigitalIdentities(pointer)
443
+ });
444
+ }
445
+ return pointers.length > 0 ? pointers : void 0;
446
+ }
447
+ /**
448
+ * Parse an ETSI TS 119 612 `TrustServiceStatusList` XML into a normalized
449
+ * {@link TrustedList}. This does NOT verify the list signature — call
450
+ * {@link verifyTrustedListSignature} first (or use {@link loadTrustedList}).
451
+ */
452
+ function parseTrustedList(xml) {
453
+ const root = new _xmldom_xmldom.DOMParser().parseFromString(xml, "application/xml").documentElement;
454
+ if (root?.localName !== "TrustServiceStatusList") throw new TrustedListParseException("Root element is not a TS 119 612 TrustServiceStatusList");
455
+ const schemeInfo = firstDescendant(root, "SchemeInformation");
456
+ const sequenceText = textOf(schemeInfo && firstDescendant(schemeInfo, "TSLSequenceNumber"));
457
+ const nextUpdate = schemeInfo && firstDescendant(schemeInfo, "NextUpdate");
458
+ const providers = [];
459
+ for (const tsp of descendants(root, "TrustServiceProvider")) {
460
+ const services = [];
461
+ for (const service of descendants(tsp, "TSPService")) {
462
+ const info = firstDescendant(service, "ServiceInformation");
463
+ if (!info) continue;
464
+ const serviceTypeIdentifier = textOf(firstDescendant(info, "ServiceTypeIdentifier"));
465
+ const serviceStatus = textOf(firstDescendant(info, "ServiceStatus"));
466
+ if (!serviceTypeIdentifier || !serviceStatus) continue;
467
+ services.push({
468
+ serviceTypeIdentifier,
469
+ serviceStatus,
470
+ serviceName: localizedName(firstDescendant(info, "ServiceName")),
471
+ digitalIdentities: parseDigitalIdentities(info),
472
+ qualifiers: parseQualifiers(info),
473
+ history: parseHistory(service)
474
+ });
475
+ }
476
+ providers.push({
477
+ name: localizedName(firstDescendant(tsp, "TSPName")),
478
+ services
479
+ });
480
+ }
481
+ return assertValidTrustedList({
482
+ tslType: textOf(schemeInfo && firstDescendant(schemeInfo, "TSLType")),
483
+ schemeOperatorName: localizedName(schemeInfo && firstDescendant(schemeInfo, "SchemeOperatorName")),
484
+ sequenceNumber: sequenceText ? Number(sequenceText) : void 0,
485
+ listIssueDateTime: textOf(schemeInfo && firstDescendant(schemeInfo, "ListIssueDateTime")),
486
+ nextUpdate: textOf(nextUpdate && firstDescendant(nextUpdate, "dateTime")),
487
+ providers,
488
+ pointersToOtherLists: schemeInfo ? parsePointers(schemeInfo) : void 0
489
+ });
490
+ }
491
+ /**
492
+ * The DER-encoded certificates a list publishes for the lists it points to —
493
+ * i.e. the trust anchors with which those lists are signed, ready to be passed
494
+ * as `trustAnchors` to `verifyTrustedListSignature`.
495
+ *
496
+ * This is the mechanism by which a trusted list distributes trust downwards: a
497
+ * verifier that has established trust in one list (for the EU LOTL, by pinning
498
+ * its signing certificates out of band) obtains the anchors of every list it
499
+ * points to without pinning them individually.
500
+ *
501
+ * ```ts
502
+ * const lotl = await loadTrustedList(lotlXml, { trustAnchors: getEuLotlTrustAnchors() })
503
+ * const esAnchors = getPointerSigningCertificates(lotl, { schemeTerritory: 'ES' })
504
+ * const esList = await loadTrustedList(esXml, { trustAnchors: esAnchors })
505
+ * ```
506
+ *
507
+ * Passing `{ tslType: TSLType.EUlistofthelists }` returns the LOTL's own
508
+ * currently published signing certificates (from its self-pointer), which is
509
+ * how a deployment refreshes its pinned set as the scheme operator rotates keys.
510
+ */
511
+ function getPointerSigningCertificates(trustedList, filter = {}) {
512
+ const certificates = [];
513
+ const seen = /* @__PURE__ */ new Set();
514
+ for (const pointer of trustedList.pointersToOtherLists ?? []) {
515
+ if (filter.location && pointer.location !== filter.location) continue;
516
+ if (filter.schemeTerritory && pointer.schemeTerritory?.toUpperCase() !== filter.schemeTerritory.toUpperCase()) continue;
517
+ if (filter.tslType && stripScheme(pointer.tslType) !== stripScheme(filter.tslType)) continue;
518
+ for (const identity of pointer.digitalIdentities) {
519
+ if (!identity.certificate || seen.has(identity.certificate)) continue;
520
+ seen.add(identity.certificate);
521
+ certificates.push(_owf_identity_common.base64.decode(identity.certificate));
522
+ }
523
+ }
524
+ return certificates;
525
+ }
526
+ /**
527
+ * Flatten a {@link TrustedList} into individual {@link TrustAnchor} entries —
528
+ * the normalized unit consumed by certificate-chain validation and AKI
529
+ * emission.
530
+ */
531
+ function getTrustAnchors(trustedList, filter = {}) {
532
+ const anchors = [];
533
+ for (const provider of trustedList.providers) for (const service of provider.services) {
534
+ if (filter.serviceStatus && !filter.serviceStatus.includes(service.serviceStatus)) continue;
535
+ if (filter.serviceTypeIdentifier && !filter.serviceTypeIdentifier.includes(service.serviceTypeIdentifier)) continue;
536
+ for (const identity of service.digitalIdentities) {
537
+ if (filter.requireCertificate && !identity.certificate) continue;
538
+ anchors.push({
539
+ certificate: identity.certificate,
540
+ subjectName: identity.subjectName,
541
+ subjectKeyIdentifier: identity.subjectKeyIdentifier,
542
+ serviceTypeIdentifier: service.serviceTypeIdentifier,
543
+ serviceStatus: service.serviceStatus,
544
+ providerName: provider.name
545
+ });
546
+ }
547
+ }
548
+ return anchors;
549
+ }
550
+ //#endregion
551
+ //#region src/profiles.ts
552
+ /** Every standard TS 119 612 service status (clause 5.5.4). */
553
+ const ALL_SERVICE_STATUSES = Object.values(ServiceStatus);
554
+ /** The standard qualified `ServiceTypeIdentifier` values (Annex D). */
555
+ const QUALIFIED_SERVICE_TYPES = Object.values(ServiceType);
556
+ /**
557
+ * Ready-made {@link ProfileRule}s for common ETSI ecosystems, so callers don't
558
+ * have to hand-write the URIs. The engine ({@link validateTrustedListProfile})
559
+ * stays profile-agnostic; these are just convenience constants you pass into it.
560
+ *
561
+ * A profile is an allowlist: the structural schema is checked first, then the
562
+ * list's `TSLType` must match and every service's type/status must be permitted.
563
+ * That fits homogeneous, curated lists well (e.g. Age Verification). For a full
564
+ * eIDAS national list — which legitimately carries withdrawn/ceased services and
565
+ * a broad mix of qualified service types — {@link euGeneric} therefore permits
566
+ * all standard ETSI statuses and qualified service types: it asserts "this is a
567
+ * well-formed EU generic list using standard ETSI URIs", not "only currently
568
+ * active CAs". Narrow further with your own {@link ProfileRule} when you need to.
569
+ */
570
+ const TrustedListProfiles = {
571
+ /**
572
+ * EU List of Trusted Lists (LOTL). Its `TSLType` is `EUlistofthelists` and it
573
+ * carries pointers to national lists rather than trust-service providers, so
574
+ * no service type/status is permitted (a conforming LOTL has no TSP services).
575
+ */
576
+ euLotl: {
577
+ name: "eu-lotl",
578
+ tslType: TSLType.EUlistofthelists,
579
+ serviceTypes: [],
580
+ serviceStatuses: []
581
+ },
582
+ /**
583
+ * A generic EU (eIDAS national) trusted list: `TSLType` `EUgeneric`, any
584
+ * standard qualified service type, any standard service status (including
585
+ * withdrawn/ceased entries that national lists retain for history).
586
+ */
587
+ euGeneric: {
588
+ name: "eu-generic",
589
+ tslType: TSLType.EUgeneric,
590
+ serviceTypes: QUALIFIED_SERVICE_TYPES,
591
+ serviceStatuses: ALL_SERVICE_STATUSES
592
+ },
593
+ /**
594
+ * EU Age Verification trusted list, per the European Commission's "AV Trusted
595
+ * List Specifications" (DIGIT.B.3). The `TSLType` (clause 5.3.3), the single
596
+ * Proof of Age Attestation service type (`paa`, clause 5.5.1) and the two
597
+ * permitted service statuses (clause 5.5.4) are fixed by that specification —
598
+ * which states the statuses "may be used to the exclusion of any other", so
599
+ * the allowlist model captures the AV profile exactly. Deployed lists have
600
+ * used `https` for the `TSLType`; the profile compares scheme-insensitively.
601
+ */
602
+ ageVerification: {
603
+ name: "eu-age-verification",
604
+ tslType: "http://trust.tech.ec.europa.eu/lists/age-verification/tsl-type",
605
+ serviceTypes: ["http://trust.tech.ec.europa.eu/lists/age-verification/service-type/paa"],
606
+ serviceStatuses: ["http://trust.tech.ec.europa.eu/lists/age-verification/service-status/recognized", "http://trust.tech.ec.europa.eu/lists/age-verification/service-status/deprecated"]
607
+ }
608
+ };
609
+ //#endregion
610
+ //#region src/verify.ts
611
+ const XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#";
612
+ let nodeDependenciesInitialized = false;
613
+ let installedCrypto;
614
+ /**
615
+ * Outside the browser, xml-core resolves DOM/XPath implementations through
616
+ * `setNodeDependencies`. Set lazily and once, so importing this package has no
617
+ * side effects until a signature is actually processed.
618
+ */
619
+ function ensureNodeDependencies() {
620
+ if (nodeDependenciesInitialized) return;
621
+ xadesjs.setNodeDependencies({
622
+ DOMParser: _xmldom_xmldom.DOMParser,
623
+ XMLSerializer: _xmldom_xmldom.XMLSerializer,
624
+ xpath
625
+ });
626
+ nodeDependenciesInitialized = true;
627
+ }
628
+ /**
629
+ * Install the WebCrypto implementation used to verify trusted list signatures
630
+ * ("bring your own crypto"), for callers that must route verification through a
631
+ * reviewed or policy-constrained engine. Call it once during start-up, before
632
+ * verifying; without it, the global Web Crypto API (`globalThis.crypto`,
633
+ * available in Node >= 20 and browsers) is used.
634
+ *
635
+ * Process-wide by necessity, not by design: xadesjs exposes a single global
636
+ * crypto engine rather than a per-call context
637
+ * (see {@link https://github.com/PeculiarVentures/xmldsigjs/issues/119}).
638
+ * A per-invocation option would look isolated while still swapping that global,
639
+ * so concurrent verifications with different engines would race; it is
640
+ * deliberately not offered. Should upstream gain per-call crypto, accepting it
641
+ * as a verification option is an additive, non-breaking change.
642
+ */
643
+ function setTrustedListCrypto(crypto) {
644
+ ensureNodeDependencies();
645
+ xadesjs.Application.setEngine("eudi-tl", crypto);
646
+ installedCrypto = crypto;
647
+ }
648
+ /**
649
+ * Make sure a crypto engine is installed before verifying. A caller-installed
650
+ * engine is never replaced — falling back to `globalThis.crypto` on every call
651
+ * that does not opt in would silently undo {@link setTrustedListCrypto}.
652
+ */
653
+ function ensureXmlSignatureEngine() {
654
+ ensureNodeDependencies();
655
+ if (!installedCrypto) setTrustedListCrypto(globalThis.crypto);
656
+ }
657
+ /**
658
+ * Verify the enveloped XAdES/XMLDSig signature of an ETSI TS 119 612 Trusted
659
+ * List. Throws {@link TrustedListSignatureException} when the signature is
660
+ * missing, invalid, or (with `trustAnchors`) not signed by a pinned scheme
661
+ * operator.
662
+ *
663
+ * Verified against a standard eIDAS national trusted list (RSA-SHA512,
664
+ * exclusive C14N, XAdES SignedProperties).
665
+ *
666
+ * Verification runs on the global Web Crypto API unless another implementation
667
+ * was installed with {@link setTrustedListCrypto}.
668
+ */
669
+ async function verifyTrustedListSignature(xml, options = {}) {
670
+ ensureXmlSignatureEngine();
671
+ const doc = new _xmldom_xmldom.DOMParser().parseFromString(xml, "application/xml");
672
+ const signatures = doc.getElementsByTagNameNS(XMLDSIG_NS, "Signature");
673
+ if (signatures.length === 0) throw new TrustedListSignatureException("No ds:Signature found in the trusted list");
674
+ const signedXml = new xadesjs.SignedXml(doc);
675
+ signedXml.LoadXml(signatures[0]);
676
+ let valid;
677
+ try {
678
+ valid = await signedXml.Verify();
679
+ } catch (error) {
680
+ throw new TrustedListSignatureException(`Trusted list signature could not be verified: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
681
+ }
682
+ if (!valid) throw new TrustedListSignatureException("Trusted list signature is invalid");
683
+ const signerCertEl = signatures[0].getElementsByTagNameNS(XMLDSIG_NS, "X509Certificate")[0];
684
+ if (!signerCertEl?.textContent) throw new TrustedListSignatureException("Trusted list signature has no X509Certificate in KeyInfo");
685
+ const signerCertificateBase64 = signerCertEl.textContent.replace(/\s/g, "");
686
+ if (options.trustAnchors && options.trustAnchors.length > 0) {
687
+ const signerDer = _owf_identity_common.base64.decode(signerCertificateBase64);
688
+ if (!options.trustAnchors.some((anchor) => (0, _owf_identity_common.compareBytes)(anchor, signerDer))) throw new TrustedListSignatureException("Trusted list signer certificate is not among the configured trust anchors");
689
+ }
690
+ return { signerCertificateBase64 };
691
+ }
692
+ //#endregion
693
+ //#region src/eu-lotl.ts
694
+ /**
695
+ * The LOTL signing certificates shipped with this package, as DER bytes ready
696
+ * to pass as `trustAnchors`.
697
+ *
698
+ * This pinned set is the root of the eIDAS trusted-list hierarchy and cannot be
699
+ * bootstrapped from the LOTL itself — a forged list would carry a forged
700
+ * self-pointer. It is published by the European Commission in the Official
701
+ * Journal; see {@link EU_LOTL_ANCHORS_PROVENANCE} for the exact act, list issue
702
+ * and expiry of the shipped set.
703
+ *
704
+ * Certificates rotate (historically every 6–24 months), so a deployment has
705
+ * three ways to stay current without waiting for a release of this package:
706
+ *
707
+ * 1. pass its own `trustAnchors`, e.g. from configuration;
708
+ * 2. after verifying a LOTL, read the currently published set from its own
709
+ * self-pointer with `getPointerSigningCertificates(lotl, { tslType:
710
+ * TSLType.EUlistofthelists })` and persist it — rotation is announced in a
711
+ * list still signed by the previous generation of keys;
712
+ * 3. follow the pivot LOTLs advertised in the list's `SchemeInformationURI`
713
+ * when the pinned set has fallen behind entirely.
714
+ */
715
+ function getEuLotlTrustAnchors() {
716
+ return EU_LOTL_SIGNING_CERTIFICATES.map((entry) => _owf_identity_common.base64.decode(entry.certificate));
717
+ }
718
+ /**
719
+ * Verify the signature of the EU List of Trusted Lists against the shipped
720
+ * signing certificates. Identical to {@link verifyTrustedListSignature} except
721
+ * that `trustAnchors` defaults to {@link getEuLotlTrustAnchors} instead of to
722
+ * "integrity only" — pass your own to override.
723
+ */
724
+ function verifyEuLotlSignature(xml, options = {}) {
725
+ return verifyTrustedListSignature(xml, {
726
+ ...options,
727
+ trustAnchors: options.trustAnchors ?? getEuLotlTrustAnchors()
728
+ });
729
+ }
730
+ /**
731
+ * Verify, parse and profile-check the EU List of Trusted Lists in one step: the
732
+ * safe entry point for the top of the hierarchy. The returned list carries the
733
+ * `PointersToOtherTSL` entries from which national list anchors are derived
734
+ * with `getPointerSigningCertificates`.
735
+ */
736
+ async function loadEuLotl(xml, options = {}) {
737
+ await verifyEuLotlSignature(xml, options);
738
+ const lotl = parseTrustedList(xml);
739
+ const profile = validateTrustedListProfile(lotl, TrustedListProfiles.euLotl);
740
+ if (!profile.valid) throw new TrustedListParseException(`Not a conforming EU List of Trusted Lists: ${profile.errors.map((error) => `${error.path}: ${error.message}`).join("; ")}`);
741
+ return lotl;
742
+ }
743
+ //#endregion
744
+ //#region src/index.ts
745
+ /**
746
+ * Verify the trusted list signature and, only if it is valid, parse it. This is
747
+ * the safe entry point: it never returns a {@link TrustedList} whose
748
+ * authenticity has not been established.
749
+ */
750
+ async function loadTrustedList(xml, options = {}) {
751
+ await verifyTrustedListSignature(xml, options);
752
+ return parseTrustedList(xml);
753
+ }
754
+ //#endregion
755
+ exports.ACTIVE_SERVICE_STATUSES = ACTIVE_SERVICE_STATUSES;
756
+ exports.DigitalIdentitySchema = DigitalIdentitySchema;
757
+ exports.EU_LOTL_ANCHORS_PROVENANCE = EU_LOTL_ANCHORS_PROVENANCE;
758
+ exports.EU_LOTL_SIGNING_CERTIFICATES = EU_LOTL_SIGNING_CERTIFICATES;
759
+ exports.ServiceHistoryInstanceSchema = ServiceHistoryInstanceSchema;
760
+ exports.ServiceStatus = ServiceStatus;
761
+ exports.ServiceType = ServiceType;
762
+ exports.TSLType = TSLType;
763
+ exports.TrustAnchorSchema = TrustAnchorSchema;
764
+ exports.TrustServiceProviderSchema = TrustServiceProviderSchema;
765
+ exports.TrustedListException = TrustedListException;
766
+ exports.TrustedListParseException = TrustedListParseException;
767
+ exports.TrustedListPointerSchema = TrustedListPointerSchema;
768
+ exports.TrustedListProfiles = TrustedListProfiles;
769
+ exports.TrustedListSchema = TrustedListSchema;
770
+ exports.TrustedListServiceSchema = TrustedListServiceSchema;
771
+ exports.TrustedListSignatureException = TrustedListSignatureException;
772
+ exports.assertValidTrustedList = assertValidTrustedList;
773
+ exports.getEuLotlTrustAnchors = getEuLotlTrustAnchors;
774
+ exports.getPointerSigningCertificates = getPointerSigningCertificates;
775
+ exports.getTrustAnchors = getTrustAnchors;
776
+ exports.loadEuLotl = loadEuLotl;
777
+ exports.loadTrustedList = loadTrustedList;
778
+ exports.parseTrustedList = parseTrustedList;
779
+ exports.setTrustedListCrypto = setTrustedListCrypto;
780
+ exports.validateTrustedList = validateTrustedList;
781
+ exports.validateTrustedListProfile = validateTrustedListProfile;
782
+ exports.verifyEuLotlSignature = verifyEuLotlSignature;
783
+ exports.verifyTrustedListSignature = verifyTrustedListSignature;
784
+
785
+ //# sourceMappingURL=index.cjs.map