Trust & audit
Trust anchors
Trust is configured as DER certificate lists on WalletConfig.trust, so the public API stays free of
X.509 types:
issuerAnchorsDer— validates issuer certificates for the Token Status List and mdoc issuer authentication. Also gates issuer-metadata verification (signed metadata → registered issuer) and the trust label written on each stored credential.readerAnchorsDer— one validator shared by two flows: remote signed VP request objects (X509RequestVerifier) and proximity mdoc reader authentication (X5cMdocReaderTrust).registrarAnchorsDer— validates a relying party's registration certificate (WRPRC) and its status list, when one rides in an OpenID4VP request'sverifier_info. With these set, a WRPRC is verified and revocation-checked, and the relying party is recorded as registrar-attested.
Chain validation is real PKIX (path building to an anchor, validity, basic constraints). A certificate that does not chain to a configured anchor is not trusted — presence of a certificate is never sufficient.
Status
- Kotlin
- Swift
when (wallet.credentials.status(id)) {
CredentialStatus.Valid -> Unit
CredentialStatus.Invalid, CredentialStatus.Suspended -> showRevoked()
CredentialStatus.Unknown -> Unit
}
switch try await wallet.credentials.status(id) {
case .valid: break
case .invalid, .suspended: showRevoked()
case .unknown: break
}
Revocation uses the IETF Token Status List — the SDK fetches and verifies the status token (signature + issuer chain), caches it, and reads the credential's index.
Transaction log
Successful and declined presentations (and issuances) are recorded for transparency (ARF / GDPR);
presentations that fail at submission are logged only when you opt in with
WalletConfig.transactionLog = TransactionLogConfig(recordFailures = true). Provide a
TransactionLogStore (persistence) via ports — the default is in-memory, so persist it to keep history
across restarts. Query history through the facade:
- Kotlin
- Swift
val history = wallet.transactions.history() // most recent first
val byRp = wallet.transactions.query(relyingPartyId = "verifier.example")
val entry = history.first()
entry.relyingParty // id, name, trusted, chain + registration: subject, purpose, entitlements, attested, statusValid, outOfScope
entry.documents // per-credential: format, type, disclosed claim paths
entry.status // SUCCESS | INCOMPLETE | ERROR
let history = await wallet.transactions.history() // most recent first
let byRp = await wallet.transactions.query(relyingPartyId: "verifier.example")
let entry = history[0]
entry.relyingParty // id, name, trusted, chain + registration: subject, purpose, entitlements, attested, statusValid, outOfScope
entry.documents // per-credential: format, type, disclosed claim paths
entry.status // .success | .incomplete | .error
The relying party records who the credential went to and whether trust was cryptographically established — for remote/DC API from the verified request object, for proximity from reader authentication. The disclosed claim paths and (optionally) raw request/response are kept for dispute resolution.