Network Working Group N. Ritz Internet-Draft Independent Intended status: Standards Track 6 July 2026 Expires: 7 January 2027 Interactive DPoP draft-ritz-idpop-01 Abstract This document describes IDPoP, an extension to DPoP [RFC9449] that uses a key derivation scheme to separate access control from identity. It mitigates credential exfiltration risks by requiring fresh hardware attestation to unseal identity keys via an interactive challenge. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 7 January 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Ritz Expires 7 January 2027 [Page 1] Internet-Draft IDPoP July 2026 Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 2. Key Material . . . . . . . . . . . . . . . . . . . . . . . . 2 3. Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . 3 3.1. Algorithm 1: DeriveKEM (Client) . . . . . . . . . . . . . 3 3.2. Algorithm 2: EncapsulateSecret (AS-A) . . . . . . . . . . 4 3.3. Algorithm 3: DeriveIdentity (Client) . . . . . . . . . . 4 4. OAuth Identity Chaining Flow . . . . . . . . . . . . . . . . 4 5. Interactive Challenge & Proofs . . . . . . . . . . . . . . . 6 6. Security Properties . . . . . . . . . . . . . . . . . . . . . 7 7. Security Considerations . . . . . . . . . . . . . . . . . . . 8 7.1. Authorization Server as Root of Trust . . . . . . . . . . 8 7.2. Encapsulated Secret Transport . . . . . . . . . . . . . . 8 7.3. "Harvest Now, Decrypt Later" and Forward Secrecy . . . . 9 7.3.1. Post-Quantum Agility . . . . . . . . . . . . . . . . 9 7.4. DPoP Proof Replay and Pre-Computation . . . . . . . . . . 9 8. Normative References . . . . . . . . . . . . . . . . . . . . 9 Appendix A. Changelog . . . . . . . . . . . . . . . . . . . . . 10 A.1. 01 . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 10 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 10 1. Introduction Standard DPoP binds tokens to keys but recent events have increased risks to exfiltration attacks where autonomous systems (such as agentic AI) leak valid credentials via prompt injection. Likewise, when malware compromises a device filesystem, attackers steal credentials and impersonate users until explicit revocation. This proposal introduces a derivation scheme separating *access control* (encapsulate/decapsulate) from *identity* (signing). 2. Key Material *seed:* High-entropy secret, encapsulated by the client's KEM Encapsulation Key (keK) and delivered to the client as sealed_seed. All HPKE seal/unseal and HKDF operations below are bound to a binding string carrying authorization intent (client_id + scope + audience), passed as the HPKE/HKDF info parameter. *Two-Stage Derivation:* 1. Access gating: keK is a KEM key pair generated natively inside the client's Target Environment, gated on producing valid Evidence (see Algorithm 1). Ritz Expires 7 January 2027 [Page 2] Internet-Draft IDPoP July 2026 2. Identity derivation: K_attest = HKDF(salt=binding, ikm=seed, info="dpop") .-------------------. | AS-A (Verifier) | 2. AS-A (RATS Verifier) | RATS Notary as | Appraises Evidence | OAuth AS | Derive keK, K_dpop '----+----+---------' Seal id seed → sealed_seed ^ | 1. Evidence | | 3. Attestation Result (AR) conveyed | | as JWT OAuth grant with: (as commitment)| - requested_cnf {jkt, keK_pub} | | - sealed_seed | v .----+--------. .-------------------. | |------------->| AS-B (OAuth) | | Client | 4. Present | Token Issuer | | (Attester) | AR grant '---+------+--------' | |<-| | ^ '------+------. +---------------+ | | 5. Validate AR | 6. Present token Issue access token | + DPoP proof | | (signed with K_dpop_priv) | v | .------+-------. 7. Validate token cnf | RS-B +------------> DPoP signature | (Resource | with K_dpop_pub | Server) | '--------------' Figure 1: OAuth Identity Chaining Flow with RATS Verifier as AS-A and "IDPoP"-aware OAuth AS-B as delegated notary _NOTE: keK controls access to seed (identity key seed material). K_attest *is* the identity. Compromise of the identity key alone is insufficient—attacker needs to demonstrate access to notarized Evidence to derive keK and unseal._ 3. Algorithms 3.1. Algorithm 1: DeriveKEM (Client) Ritz Expires 7 January 2027 [Page 3] Internet-Draft IDPoP July 2026 Input: Evidence (attested by the Target Environment) Output: (keK_priv, keK_pub) (keK_priv, keK_pub) = X25519.KeyGen() // generated inside the Target Environment The Target Environment binds keK_pub via attestation, e.g.: Evidence = Attest(claims={ keK_pub }, signing_key=aeK) keK_priv never leaves the Target Environment and is not derived by feeding Evidence into an external HKDF call; this keeps the scheme compatible with TPMs and Secure Enclaves, which do not expose internal seeds for software-side key derivation. 3.2. Algorithm 2: EncapsulateSecret (AS-A) Input: binding (client_id + scope + audience), keK_pub (from client attestation) Output: (sealed_seed, K_dpop_pub) seed = Random(32) sealed_seed = HPKE.Seal(recipient_pk=keK_pub, info=binding, plaintext=seed) K_dpop_priv = HKDF(salt=binding, ikm=seed, info="dpop") K_dpop_pub = Ed25519.Public(K_dpop_priv) 3.3. Algorithm 3: DeriveIdentity (Client) Input: binding (client_id + scope + audience), keK_priv, sealed_seed Output: K_dpop_priv seed = HPKE.Unseal(recipient_sk=keK_priv, info=binding, ciphertext=sealed_seed) K_dpop_priv = HKDF(salt=binding, ikm=seed, info="dpop") *Convergence:* Client derives K_dpop_priv from (binding, seed) only after unsealing the encapsulated seed. 4. OAuth Identity Chaining Flow *Setup (Client → AS-A):* 1. Client generates attestation Evidence 2. Client: (keK_priv, keK_pub) = DeriveKEM(Evidence) 3. Client sends attestation to AS-A with keK_pub *Notarization (RATS Verifier as AS-A):* 1. AS-A Appraises attestation Evidence Ritz Expires 7 January 2027 [Page 4] Internet-Draft IDPoP July 2026 2. AS-A: (sealed_seed, K_dpop_pub) = EncapsulateSeed(binding, keK_pub) 3. AS-A creates JWT grant to AS-B: { "iss": "https://as-a.example", "sub": "client_id", "aud": "https://as-b.example", "iat": 1706745600, "exp": 1706745660, "jti": "grant-7f3a9c", "requested_cnf": { "jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I", "idpop_managed_keysets": { "kem-encapsulation-keys": [ { "kty": "OKP", "crv": "X25519", "use": "enc", "kid": "keK_public_01", "x": "l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs" } ] } } } *Token Issuance (AS-B):* 1. AS-B validates grant, issues DPoP-bound access token: { "access_token": "eyJ...(JWT with cnf.jkt inside)...", "token_type": "DPoP", "expires_in": 3600 } The access token JWT contains: Ritz Expires 7 January 2027 [Page 5] Internet-Draft IDPoP July 2026 { "iss": "https://as-b.example", "sub": "client_id", "aud": "https://rs-b.example", "iat": 1706745600, "exp": 1706749200, "cnf": { "jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I", "idpop_managed_keysets": { "kem-encapsulation-keys": [ { "kty": "OKP", "crv": "X25519", "use": "enc", "kid": "keK_public_01", "x": "l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs" } ] } } } Here, jkt validates the DPoP signature (standard DPoP), and idpop_managed_keysets enables the IDPoP liveness challenge. 5. Interactive Challenge & Proofs *Interactive Challenge (AS-B → Client):* 1. Client sends request with DPoP proof (no nonce or cached nonce) 2. AS-B decides: "I need hardware liveness proof" 3. AS-B → 401 Unauthorized WWW-Authenticate: DPoP error="use_dpop_nonce" DPoP-Nonce: *Client Proof:* 1. seed = HPKE.Unseal(keK_priv, sealed_seed) (proves fresh Evidence) 2. Client extracts sealed nonce from header 3. Client: nonce = HPKE.AuthUnseal(nonce_sealed, keK_priv, AS_B_pubkey) 4. Client: K_dpop_priv = HKDF(binding, seed, "dpop") Ritz Expires 7 January 2027 [Page 6] Internet-Draft IDPoP July 2026 5. Client creates new DPoP proof with unsealed nonce and retries: The DPoP proof JWT uses a proposed new type, idpop+jwt, and carries the public Identity Key (K_dpop) in its header: { "typ": "idpop+jwt", "alg": "EdDSA", "jwk": { "kty": "OKP", "crv": "Ed25519", "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" } } The corresponding payload: { "jti": "e1j3V_bKic8-LAEB", "htm": "POST", "htu": "https://rs-b.example/api", "iat": 1706745600, "ath": "fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo", "nonce": "kH8Ws3xYnE2f7d9pQ1vR5jL4mT6oU0aC8bN3gZ7yXsA" } *Verification (AS-B or RS-B):* 1. Verify DPoP signature with K_dpop_pub (from token's cnf.jkt) 2. Verify proof.nonce == SHA256(expected_nonce) 3. Accept request _Note: The interactive challenge (Steps 8-10) introduces a round- trip. To mitigate latency, this challenge MAY be performed once per session or upon detecting high-risk context. The resulting nonce acts as a session binding signal for subsequent DPoP proofs, reducing overhead for high-frequency API calls._ 6. Security Properties 1. *No durable secrets at AS-A.* Post-issuance compromise of AS-A yields no client key material. RATS Verifier (AS-A) computes K_dpop_priv transiently, extracts K_dpop_pub, discards both K_dpop_priv and secret seed material (seed). Ritz Expires 7 January 2027 [Page 7] Internet-Draft IDPoP July 2026 2. *Sealed grant confidentiality.* Interception without keK_priv yields nothing. sealed_seed is HPKE-encrypted to keK_pub. 3. *Attestation-bound unsealing.* Stolen sealed_seed without device access is unusable. keK_priv is generated and retained solely inside the Target Environment, gated on producing valid Evidence. Unsealing seed requires fresh hardware attestation. 4. *Key separation.* keK controls access. K_dpop asserts identity. Compromise of signing key doesn't grant unsealing; compromise of unsealing requires live Evidence. 5. *Convergent derivation.* No key transport. Client derives K_dpop from (binding, seed) independently. 7. Security Considerations 7.1. Authorization Server as Root of Trust The architecture described in this document leverages the Authorization Server (AS-A in the RATS flow, or the OAuth AS) as a Trusted Third Party (TTP). This aligns with the standard OAuth 2.0 threat model [RFC6819], where the AS is already trusted to generate access tokens, sign ID tokens, and manage client credentials. While IDPoP introduces the generation and sealing of the Identity Key seed by the AS, this does not introduce a new root of trust. An AS capable of issuing a valid access_token can already impersonate the user to the Resource Server. Therefore, entrusting the AS with the transient generation of the seed is consistent with its existing role. The security goal of IDPoP is not to protect the client _from_ the AS, but to protect the client's credentials from exfiltration _after_ issuance. 7.2. Encapsulated Secret Transport This specification utilizes a Key Transport pattern where the Identity Key material (seed) is generated by the server and transmitted to the client in an HPKE-sealed envelope (sealed_seed). While Key Transport is sometimes disfavored in comparison to Key Agreement, it is necessary here to bind the identity to the specific hardware attestation presented by the client. Unlike a KEM shared secret consumed once for a transient liveness proof, seed is re- unsealed on each interactive challenge to re-derive the persistent signing key K_dpop, which remains valid for the life of the access token. Ritz Expires 7 January 2027 [Page 8] Internet-Draft IDPoP July 2026 The security of this transport relies on hardware binding: the seed is sealed to keK_pub, which is generated and retained inside the client's hardware-bound Target Environment. Even if sealed_seed is intercepted, it remains inert without the corresponding hardware- bound private key keK_priv. 7.3. "Harvest Now, Decrypt Later" and Forward Secrecy Encrypted transport of secrets is subject to "Harvest Now, Decrypt Later" (HNDL): an adversary records encrypted traffic today to decrypt it once quantum computing breaks current asymmetric primitives (e.g., X25519). The impact of HNDL on IDPoP is limited by the short lifetime of the identity key it protects. seed is used solely to derive the DPoP signing key (K_dpop), which is only useful for signing DPoP proofs during the validity period of the associated access token (defined by exp). If an adversary breaks the KEM years in the future and recovers a historical seed, the associated access token will have long since expired; unlike confidentiality keys protecting persistent data, recovering an authentication key after the session window has closed yields no advantage, provided the AS enforces standard expiration (exp) and replay protection (jti). 7.3.1. Post-Quantum Agility To further mitigate HNDL risks and ensure long-term resistance, implementations SHOULD support cryptographic agility in the HPKE configuration. Implementations can adopt hybrid KEMs such as X-Wing (combining X25519 and ML-KEM-768) for post-quantum resistance alongside classical security guarantees. The alg parameter in the attestation request or metadata allows the client and AS to negotiate Quantum-Resistant KEMs (e.g., ML-KEM) as they become standardized, keeping sealed_seed secure against future quantum cryptanalysis. 7.4. DPoP Proof Replay and Pre-Computation To prevent an attacker with temporary access to the signing key (or the ability to predict nonces) from pre-computing proofs, this specification mandates the use of HPKE-sealed nonces. Sealing the nonce to the client's keK_pub ensures that only a client with active access to the hardware-bound keK_priv can recover the nonce and sign the proof. This also limits the impact of a stolen cached K_dpop: malware holding it cannot pre-generate valid proofs for future requests, since it cannot decrypt future nonces without invoking the hardware anchor. 8. Normative References Ritz Expires 7 January 2027 [Page 9] Internet-Draft IDPoP July 2026 [I-D.ietf-oauth-identity-chaining] Schwenkschuster, A., Kasselman, P., Burgin, K., Jenkins, M. J., Campbell, B., and A. Parecki, "OAuth Identity and Authorization Chaining Across Domains", Work in Progress, Internet-Draft, draft-ietf-oauth-identity-chaining-16, 26 June 2026, . [RFC6819] Lodderstedt, T., Ed., McGloin, M., and P. Hunt, "OAuth 2.0 Threat Model and Security Considerations", RFC 6819, DOI 10.17487/RFC6819, January 2013, . [RFC9180] Barnes, R., Bhargavan, K., Lipp, B., and C. Wood, "Hybrid Public Key Encryption", RFC 9180, DOI 10.17487/RFC9180, February 2022, . [RFC9449] Fett, D., Campbell, B., Bradley, J., Lodderstedt, T., Jones, M., and D. Waite, "OAuth 2.0 Demonstrating Proof of Possession (DPoP)", RFC 9449, DOI 10.17487/RFC9449, September 2023, . Appendix A. Changelog A.1. 01 * restructured draft * updated key and key input material names Acknowledgments TODO Author's Address Nathanael Ritz Independent Email: ietf@nritz.com Ritz Expires 7 January 2027 [Page 10]