Skip to content
ADR-0025Architecture decisionAcceptedversion 1.0.02 October 2026

Context ​

Today the Tamga wallet obtains a single WUA (Wallet Unit Attestation)Cüzdan sağlayıcısının bir cüzdan birimi ve anahtarlarının güvenliği hakkındaki attestation'ı; güncel AB metinlerinde WIA ve key attestation olarak ikiye ayrılır. valid for 30 days from the cüzdan sağlayıcısı (wallet provider)Cüzdanı sunan ve cüzdan ile anahtar kanıtlarını imzalayan kuruluş. Tamga Wallet ağın ilk cüzdanıdır. (wallet.tamga.network). It shows the same WUA to every institution when receiving credentials (D-CRED-6, SPEC-PROTO-0001 §11.1). The EU gap analysis (H1) found this to be one of the largest gap clusters:

  • topic 9: 22 items,
  • topic 38: 15 items,
  • VCR_01a/03a/07,
  • WIAM_06/10.

Gaps against EU TS3 (v1.5.2) and ARF (Architecture and Reference Framework)Rolleri, mimariyi, güven modelini ve kuralları anlatan belge seti. Tamga ARF, AB ARF'sinin düzenini izler. 3.0:

  1. Lifetime and unlinkability. A WIA (Wallet Instance Attestation)Cüzdan sağlayıcısının imzaladığı, cüzdan kurulumunun gerçek olduğunu bildiren kısa ömürlü beyan; belge veren, belgeyi vermeden önce denetler. must live less than 24 hours. The same WIA must not be shown to more than one institution; otherwise institutions can link the same wallet across each other.
  2. No key attestation. The wallet provider must state in a signed key_attestation where the belge (credential)Belge verenin imzaladığı ve kişinin cüzdanında duran dijital belge; kişi yalnız istenen alanları gösterir. keys are stored (OpenID4VCI (OpenID for Verifiable Credential Issuance)Belge verenin belgeyi cüzdana teslim ettiği protokol. Annex D). Today the institution reads this from a claim in the WUA.
  3. No revocation. The wallet provider must publish a iptal listesi (status list)Her belgenin tek bir konumu olduğu sıkıştırılmış, imzalı liste; geçerli, askıda ya da iptal olduğunu söyler. for WIAs and KAs and be able to revoke a wallet unitBir cüzdanın belirli bir cihazdaki kurulumu. at the user's request (VCR_07, WURevocation_10). For this it must know which WIA belongs to which unit.

Project management approved the H1 plan (P3: this work) and asked to move on to the next items.

Decision ​

K1 — Wallet unit registration ​

On first setup the wallet registers a unit key with the wallet provider. This key is used only between the wallet and the provider and is never shown to an institution. The provider keeps a unit record:

  • the fingerprint of the unit key,
  • solution and version,
  • registration time,
  • revocation state,
  • the WIA status list entries issued to the unit.

No personal data is kept. Requests about the unit are signed with the unit key.

K2 — WIA (Wallet Instance Attestation) ​

  • Format: OpenID4VCI 1.0 Annex E (oauth-client-attestation+jwt), TS3 §2.3.1 fields: sub, wallet_name, wallet_version, wallet_link, wallet_solution_certification_information, client_status {status, exp}, cnf.jwk.
  • Lifetime < 24 hours (Tamga: 23 hours). client_status.exp at least 31 days ahead (Tamga: 60 days).
  • A new WIA for every credential transaction: a new PoP (proof of possession) key and a new, unlinkable status list entry. The per-institution reuse option is not used, so the provider does not learn how many institutions the wallet talks to.
  • The provider keeps the mapping between status list entries and the unit; when the unit is revoked, all its entries are revoked.

K3 — KA (key attestation) ​

  • Format: OpenID4VCI 1.0 Annex D (keyattestation+jwt), TS3 §2.3.2 fields:
    • attested_keys (all credential keys in a batch),
    • key_storage / user_authentication (ISO 18045 levels),
    • certification,
    • key_storage_status {status, exp}.
  • Honest level: today the keys are in a software store (S-9). The KA says key_storage: ["iso_18045_basic"] and carries no certification. The level rises with the move to secure hardware (Z1).
  • Revocation: one shared entry per storage type (TS3 Option 1). Software store, Secure Enclave and StrongBox each have one entry. The unit identity cannot be derived from the KA.
  • Transport: key_attestation in the header of the jwt proof. The proof is signed with attested_keys[0]; a batch is requested with a single proof. Each key appears in only one KA. A KA is used once.

K4 — Status lists and revocation at the user's request ​

  • The provider publishes two Token Status Lists (WIA entries and KA storage types). It signs them with its own key, which is registered in the güven listesi (trust list)Bir ülkenin kök sertifikalarını, belge verenlerini ve kayıtlı relying party'lerini taşıyan imzalı liste. Bugün Tamga'da güven bu listelere dayanır; ortak defter sonra gelir.. The WIA list has at least 10,000 entries.
  • The user can choose "Revoke this wallet" in the wallet (handing over or selling the device). The unit and all its WIA entries are revoked.
  • Revocation from a lost or stolen device requires a user account (WIAM_06); left to a later step.

K5 — Issuers ​

  • At the PAR (Pushed Authorization Request)Yetkilendirme isteğinin önce sunucuya gönderildiği OAuth adımı; içerik tarayıcı adresinde görünmez. and token endpoints the WIA is verified: signature, provider key in the trust list, validity period, PoP (cnf), client_status not revoked.

  • At the credential endpoint, if the proof header carries a KA, the following are verified:

    • signature and provider key,
    • the proof's signature with attested_keys[0] and the nonceBir kez kullanılan rastgele değer; doğrulayıcı gönderir, cüzdan imzalar, böylece eski bir gösterme yeniden kullanılamaz.,
    • key_storage_status not revoked,
    • the key_storage level meets the institution's minimum.

    Credentials are bound to attested_keys.

  • Metadata: proof_types_supported.jwt.key_attestations_required {key_storage, user_authentication} (ISSU_27d).

  • Transition: the proof format without a KA is accepted until the pilot, then removed.

  • The key_storage the institution read from WUA claims is now read from the KA.

K6 — Refresh token binding ​

The ADR-0023 refresh token is today also bound to the WUA sub. Because each transaction uses a new WIA key, this binding becomes the condition credential-specific DPoP (Demonstrating Proof of Possession)Erişim belirtecini bir anahtara bağlama yöntemi; çalınan belirteç o anahtar olmadan kullanılamaz. key + a valid, unrevoked WIA. AR2's rule "the wallet attestation is verified on every refresh" still applies.

Options considered ​

OptionResultWhy
A single 30-day WUArejectedNot TS3-compliant; linkable across institutions; no revocation
WIA entry reused per institutionrejectedThe provider learns how many institutions the wallet talks to and how often
A separate status list entry per KA (Option 2)laterFor key-store revocation at the user's request; together with the hardware key (Z1)
A new WIA per transaction + one KA entry per storage typeacceptedLeast information; the most privacy-friendly option TS3 allows

Invariants ​

CodeRule
WIA1A WIA lives less than 24 hours; every credential transaction uses a WIA with a new PoP key and a new status list entry.
WIA2The wallet provider keeps no personal data in the unit record; when a unit is revoked, all WIA entries issued to it are revoked.
WIA3The key storage level in the KA states the truth; an unverified claim is not written into a KA.
WIA4An issuer does not issue a credential against a revoked WIA or KA.

Consequences ​

  • apps/wallet-provider:
    • unit registration, /wia, /ka, /units/revoke, /units/delete,
    • two status lists,
    • a persistent state file.
  • @tamga-network/trust (re-exported by @tamga-network/issuer): WIA and KA verification, revocation checks. The institution issuer and the identity service use this format.
  • wallet-core: unit key, per-transaction WIA, KA request, proof with KA. Wallet: registration, "Revoke this wallet".
  • SPEC-PROTO-0001 §11.1 and D-CRED-6 are written according to this decision.
  • ARF: topics 9, 38 and VCR_01a/03a/07 are largely met. WSCD and device attestation are in Z1.

Status ​

Accepted — 2026-09-29. Approved by project management (H1 plan, P3). DECISIONS: D-CRED-7.