<!-- PDF-show
\newpage
-->

# PID Option B': Authenticated Channel with Cloud Support

## Basic Idea

This flow describes a flow that issues PID credentials in ISO mdoc / SD-JWT VC
format on-demand when the presentation request is received. It uses the
OpenID4VCI protocol for issuance and the OpenID4VP protocol for presentation.
The PID credentials are HMAC'd by the PID Provider for the specific transaction.

To improve user experience and prevent the users from tapping an eID card every
time a Credential needs to be presented, the concept of a seed credential is
introduced. A seed credential can be used for a limited period of time to
generate presentations instead of the national eID. Such seed credential is
derived from the national eID and stored on the mobile device.

To secure the seed credential, the user must set up a new PID PIN, which is
verified by the PID provider on the server side during on-demand issuance.

## Lifecycle

The credential is created on-demand by the PID Provider, i.e., a new credential
is created for every transaction. The credential is not stored in the wallet. It
is bound to the specific transaction through not only the nonce and audience,
but also the symmetric key used for HMAC'ing, which is derived from ephemeral
keys of the RP and PID Provider.

The seed credential issued and signed by the PID provider should only have a
limited lifetime and should be bound to the same key as the wallet attestation
issued by the wallet provider and to the key derived from the user PID PIN. The
seed credential contains all available PID attributes and is intended
exclusively for presentation to the PID provider, therefore it is a credential
(in JWT format) that does not provide a mechanism for selective disclosure.

## Credential formats

Two solutions are described:

- **ISO mdoc:** The ISO mdoc credential format is used with:
    - issuerAuth as issuer data authentication, a COSE_Sign1 signature over the
    MobileSecurityObject (see ISO 23220-4 7.1.3.4.2.1) signed by the PID
    Provider
        - no signed hashes are transmitted, i.e., `digestAlgorithm` and
      `valueDigests` are omitted
    - deviceMAC as mdoc authentication method, a COSE_Mac0 MAC over the
    deviceAuthentication data (see ISO 18013-5 9.1.3.5) signed by the PID
    Provider
        - containing the PID data
- **SD-JWT VC:** The SD-JWT VC credential format is used with:
    - SD-JWT issued by the PID Provider, a JOSE JWS with MAC key derived from
    ECDH* and signed by the PID Provider
        - containing the PID data
        - the Wallet provides an ephemeral, asymmetric key to the PID Provider for
      the key binding
    - KB-JWT issued by the Wallet, a JOSE JWS using digital signature and signed
    by the Wallet
        - containing nonce and audience of the Relying Party
        - containing a hash of the SD-JWT and the selected disclosures

Note that in mdoc, it is PID Provider and not the Wallet who creates
DeviceSigned containing only the selectively disclosed data based on the
Verifier's request and user consent. This is different from ISO 18013-5, where
it is the Wallet who creates DeviceSigned. It is PID Provider who creates
IssuerSigned.

In SD-JWT, it is PID Provider who creates SD-JWT and the Wallet who creates
KB-JWT.

The establishment of the authenticated channel is defined:

- for mdoc, in Chapter 9.1.3.5 in ISO 18013-5, in the mdoc MAC Authentication
  section
- for SD-JWT, the IETF Draft for [Designated Verifier
  Signatures](https://datatracker.ietf.org/doc/draft-bastian-dvs-jose/) defines
  a JOSE algorithm to be used

## Cryptographic Formats

Long-Term keys:

- **PID Provider has long-term key pair** $(pp\_pub, pp\_priv)$ which is used
    - to sign over the ephemeral issuer key, authenticating it for credential
    issuance
    - sign the **Seed PID-Credential**
- **RP has long-term key pair** $(rp\_pub, rp\_priv)$ which is used
    - to sign over the authorization request, authenticating its contents
- **Wallet Instance has long-term device bound key pair** $(device\_pub,
  device\_priv)$ which is used
    - to generate proof of possession of wallet attestation
    - to bind the PIN proof to the device
- **Wallet Instance has long-term AES key** $(pin\_salt)$ which is used
    - to derive the `pin_derived_eph_priv` used as PoP of PID PIN
- **Wallet Backend long-term key pair** $(wp\_pub, wp\_priv)$ which is used
    - to sign wallet instance's wallet attestations
- **Wallet Instance or Wallet Backend long-term key pair** $(dpop\_pub,
  _dpop\_priv)$ which is used
    - as the DPoP key

Transaction-specific keys:

- **Relying Party generates ephemeral key pair** $(rp\_eph\_pub, rp\_eph\_priv)$
  which is used
    - as contribution to HMAC key
- **PID Provider generates ephemeral key pair** $(pp\_eph\_pub, pp\_eph\_priv)$
  which is used as contribution to HMAC key
- **Wallet generates ephemeral key pair** $(kb\_eph\_pub, kb\_eph\_priv)$ which
  is used
    - to sign KB-JWT (SD-JWT)
- **Wallet Instance generates ephemeral key derived from user PID PIN**
  $(pin\_derived\_eph\_pub, pin\_derived\_eph\_priv)$ which is used
    - to generate PIN proof of possession

Note: The key derived from user PIN is not stored by the Wallet Instance,
instead it is generated every time the user enters the PIN.

Artifacts:

- PID Provider creates **certificate for ephemeral issuer key**: $x5c\_header :=
  \text{sign}(pp\_eph\_pub)_{pp\_priv}$
- **Key for authenticating SD-JWT:** $hmac\_key := \text{ecdh}(pp\_eph\_priv,
  rp\_eph\_pub)$
- PID Provider creates **SD-JWT**: $sd\_jwt := \text{hmac}(x5c\_header,
  \mathit{eID\_data}, kb\_eph\_pub)_{hmac\_key}$ and disclosures
- Wallet Backend creates **Wallet Attestation** including $(device\_pub)$ and
  signed with $(wp\_priv)$, Wallet Attestion is stored by Wallet Instance
- PID Provider creates **Seed PID-Credential** as JWT including $(device\_pub)$
  and signed with $(pp\_priv)$, which is used to generate the credentials in the
  "On-the-fly PID Issuance" for presentation. Content of the Seed
  PID-Credential:
    - eID data of the holder (PID data set)
    - Key for the holder binding of the seed credential $(device\_pub)$

<!-- PDF-show
\newpage
-->

### Dependencies
#### SD-JWT
*TODO: May want to expand to include metadata.*

```plantuml
digraph G {
  node [shape=box]

  subgraph cluster_wallet {
    style=filled
    color=lightgreen
    label="Wallet"

    subgraph cluster_wscd {
      style=filled
      color=lightyellow
      label="WSCD"
      device_key [label="🗝 (device_priv, device_pub)"]
      dpop_key [label="🗝 (dpop_priv, dpop_pub)"]
    }

    pin_salt [label="🗝 PIN salt key"]
    pin_key [label="🗝 (pin_derived_eph_priv, pin_derived_eph_pub)"]
    w_attest_POP[label="wallet attestation POP (wallet attestation nonce)"]

    kb_key [label="🗝 (kb_eph_priv, kb_eph_pub)"]
    kb_jwt [label="KB-JWT(nonce,aud,hash(SD-JWT,disclosures))"]

    dpop [label="DPoP proof (dpop_nonce)"]
  }

  subgraph cluster_rp {
    style=filled
    color=orchid
    label="Relying Party"

    rp [label="🗝 (rp_eph_priv, rp_eph_pub)"]
  }

  hmac [label="🗝 HMAC key"]

  subgraph cluster_pid_provider {
    style=filled
    color=lightblue
    label="PID Provider"

    pp [label="🗝 (pp_priv, pp_pub)"]
    seed_C [label="seed credential (device_pub, pin_derived_eph_pub)"]
    session_id [shape=record,label="{pid_issuer_session_id}"]

    pp_eph [label="🗝 (pp_eph_priv, pp_eph_pub)"]
    pp_cert [label="key certificate for pp_eph"]
    sd_jwt [label="SD-JWT(eID Data, kb_eph_pub)"]
  }

  pin_salt->pin_key [label="derived with PIN"]
  device_key->w_attest_POP [label="sign"]
  device_key->session_id [label="sign"]
  pin_key->session_id [label="sign"]
  rp->hmac [label="ecdh-ka"]
  pp->seed_C [label="sign"]
  dpop_key->dpop [label="sign"]

  kb_key->kb_jwt [label="sign"]
  pp_eph->hmac [label="ecdh-ka"]
  pp->pp_cert [label="sign"]
  hmac->sd_jwt [label="sign"]

}

```

#### mdoc

*TODO: May want to expand to include metadata.*

```plantuml
digraph G {
  node [shape=box]

  subgraph cluster_wallet {
    style=filled
    color=lightgreen
    label="Wallet"

    subgraph cluster_wscd {
      style=filled
      color=lightyellow
      label="WSCD"
      device_key [label="🗝 (device_priv, device_pub)"]
      dpop_key [label="🗝 (dpop_priv, dpop_pub)"]
    }

    pin_salt [label="🗝 PIN salt key"]
    pin_key [label="🗝 (pin_derived_eph_priv, pin_derived_eph_pub)"]
    w_attest_POP[label="wallet attestation POP (wallet attestation nonce)"]

    dpop [label="DPoP proof (dpop_nonce)"]
  }

  subgraph cluster_rp {
    style=filled
    color=orchid
    label="Relying Party"

    rp [label="🗝 (rp_eph_priv, rp_eph_pub)"]
  }

  hmac [label="🗝 HMAC key"]

  subgraph cluster_pid_provider {
    style=filled
    color=lightblue
    label="PID Provider"

    pp [label="🗝 (pp_priv, pp_pub)"]
    seed_C [label="seed credential (device_pub, pin_derived_eph_pub)"]
    session_id [shape=record,label="{pid_issuer_session_id}"]

    pp_eph [label="🗝 (pp_eph_priv, pp_eph_pub)"]
    issuerAuth [label="issuerAuth(pp_eph_pub)"]
    devAuth [label="deviceAuth(eID Data, SessionTranscript)"]

  }

  pin_salt->pin_key [label="derived with PIN"]
  device_key->w_attest_POP [label="sign"]
  device_key->session_id [label="sign"]
  pin_key->session_id [label="sign"]
  rp->hmac [label="ecdh-ka"]
  pp->seed_C [label="sign"]
  dpop_key->dpop [label="sign"]

  pp_eph->hmac [label="ecdh-ka"]
  hmac->devAuth [label="sign"]
  pp->issuerAuth [label="sign"]

}

```

<!-- PDF-show
\newpage
-->

## Sequence Diagrams and Step-by-Step Description of Each Step

Each step of the protocol will be explained using a sequence diagram followed by
a step-by-step description.

### Wallet Activation

[User Journey: Wallet Activation - Authenticated Channel -
Cloud](../user_journeys/PID-AuthenticatedChannel-cloud-initialization.png)

To initialize the wallet, the Wallet obtains wallet attestation as defined in
[Wallet Attestation](Wallet-Attestation.md).

### PID Seed-Credential Issuance

#### PID Seed-Credential Issuance Sequence Diagram

[User Journey: PID Issuance - Authenticated Channel -
Cloud](../user_journeys/PID-AuthenticatedChannel-cloud-issuance.png)

```plantuml
@startuml
'Ensure messages are not too wide
skinparam maxMessageSize 200
skinparam wrapWidth 300

'Macro for colored [TLS] block
!function tls()
!return "<color #118888>[TLS]</color>"
!endfunction

'Align text on arrows to center
skinparam sequenceMessageAlign center

'padding between boxes
skinparam BoxPadding 100

autonumber "<b>(000)"

title PID Seed Credential Issuance over OpenID4VCI

participant u [
                PID Holder
                ----
                ""PIN: (//user_pin//)""
            ]
participant w [
                User's EUDI Wallet Instance\
                (eID-Client)
                ----
                ""Device Key: (//device_pub//, //device_priv//)""
                ""Wallet Attestion bound to //device_pub//""
                ""PIN Salt: //pin_salt//""
            ]
participant i  [
                PID Provider
                (eService+eID Server)
                ----
                ""Long-term Key: (//pp_pub//, //pp_priv//)""
            ]


u --> w : open wallet, unlock wallet
hnote over w #dfd: Screen: launch_wallet
hnote over w #dfd: Screen: unlock_wallet
u --> w : request issuance of PID
hnote over w #dfd: Screen: credential_catalog


note over w,i: PID Issuer and EUDI Wallet have inherent trust relationship, metadata may be pre-configured or retrieved

w -> i : tls() HTTP POST </session_endpoint> wallet attestation nonce
i -> i : generate and store nonce
i -> w : tls() HTTP 200 <wallet attestation nonce>

w -> w : create and sign wallet attestation PoP JWT (incl. wallet attestation nonce)

w -> i : tls() HTTP POST PAR (PKCE code_challenge, wallet attestation JWT, wallet attestation PoP JWT, redirect_uri)
i -> i : verify wallet attestation & PoP \ncheck Wallet Provider solution status on trust list

i -> w : tls() HTTP 200 request_uri

note right : Attestation guarantees with high certainty that Wallet is trustworthy and not manipulated

w -> i : tls() HTTP GET <OpenID4VCI Authorization Request(request_uri)>

hnote over w #dfd: Screen: consent_add_credential
hnote over w #dfd: Screen: eid_start

'newpage

group Read eID or Smart eID acc. to BSI TR-03130
i -> w : tls() starting the eID Process
w <-> i : eID Process
u <--> w : <eID-PIN>
hnote over w #dfd: Screen: eid_pin
w <-> i : eID Process
note left : all PID attributes are requested
w -> i : tls() HTTP GET finishing the eID process with refreshUrl
hnote over w #dfd: Screen: eid_nfc_data
end

'newpage
i -> w : tls() HTTP 302 <OpenID4VCI Authorization Response(authorization code)>

group Generate initial DPoP nonce
  w -> w : generate placeholder DPoP proof with generic (not HSM-bound) key pair

  w -> i : tls() HTTP POST <Token Request(DPoP Header with placeholder proof, authorization_code, PKCE code_verifier)>
  i -> i: generate and store dpop_nonce
  i -> w : tls() HTTP 400 <Bad Request (DPoP nonce Header with dpop_nonce, error: "use_dpop_nonce")>

  note left : The Wallet should check at this point, whether the Token Endpoint delivered the expected error and nonce. If not, this needs to be handled (retry or abort gracefully).
  w -> w: store dpop_nonce
end

w -> w: prepare DPoP proof JWT with //dpop_pub//, dpop_nonce, iat and sign with //dpop_priv//

w -> i : tls() HTTP POST <Token Request(authorization code, PKCE code_verifier, DPoP Header)>

i -> i: generate and store dpop_nonce
i -> i : lookup authorization code\ngenerate TokenResponse with DPoP access token\nverify PKCE challenge\nverify DPoP proof
i -> w : tls() HTTP 200 <Token Response(DPoP nonce header with dpop_nonce, DPoP-bound access_token, c_nonce)>

group set PID PIN
w -> w : generate and store AES key: //pin_salt//
u <--> w : set PID PIN
hnote over w #dfd: Screen: set_pid_pin
w -> w : generate key pair (//pin_derived_eph_pub//, //pin_derived_eph_priv//) from KDF(encrypt_AES(//pin_salt//, PIN), PIN)

w -> w : generate PoP for pin derived ephemeral key - sign(nonce, //device_pub//) <sub>//pin_derived_eph_priv//</sub>
w -> w : generate PoP for device_key - sign(nonce, //pin_derived_eph_pub//) <sub>//device_priv//</sub>
end

w -> w : generate credential response encryption key pair (//cre_eph_pub//, //cre_eph_priv//)
w -> w : create credential_response_encryption object with jwk containing //cre_eph_pub//

w -> w: prepare DPoP proof JWT with //dpop_pub//, dpop_nonce, iat and sign with //dpop_priv//

w -> i : tls() HTTP POST <Credential Request(DPoP Header with proof, DPoP-bound access token, new credential format "seed_credential", //pin_derived_eph_pub//, PoP for pin derived ephemeral key, proof (PoP for device_key), credential_response_encryption object>

i -> i: lookup access token and verify DPoP proof
i -> i: check signatures on the PoPs
i -> i: Set up retry counter and save together with //pin_derived_eph_pub// using hash(//device_pub//) as identifier

i -> i: generate PID seed credential with eID data, //device_pub// and signed by //pp_priv//
i -> i: generate encrypted credential response JWT using the values received in the credential_response_encryption object

i -> w : tls() HTTP 200 <JWT(Credential Response(seed credential JWT))>
w -> w : decrypt credential response JWT and retrieve seed credential JWT

w -> w : store seed credential
hnote over w #dfd: Screen: success
hnote over w #dfd: Screen: home

@enduml
```

<!-- PDF-show
\newpage
\blandscape
-->

### PID Seed-Credential Issuance Step-by-Step Description

1. The User opens the Wallet App
2. The User requests a PID issuance
3. The Wallet requests a fresh nonce for the wallet attestation nonce from the
   PID Provider (wallet attestation nonce)
4. The PID Provider generates a fresh nonce linked to the issuance session
5. The PID Provider returns the wallet attestation nonce to the Wallet
6. The Wallet generates a Wallet Attestation PoP and signs it with
   *device_priv*; containing
   - audience
   - expiration time
   - wallet attestation nonce
7. The wallet sends the Pushed Authorization Request to the PID Provider;
   containing
   - PKCE code_challenge
   - wallet attestation + PoP
   - redirect_uri
8. The PID Provider verifies the wallet attestation and its proof of possession
   and validates the certification status of the Wallet Solution on a trust list
9. The PID Provider returns a request_uri that is bound to the Pushed
   Authorization Request
10. The Wallet sends the Authorization Request containing the PAR request_uri.
11. The Wallet starts user authentication process using eID by sending a
    redirect (303) to the eID Server in response to the Authorization Request.
12. Further communication is exchanged to perform the eID process.
13. The user provides the eID PIN to the wallet app.
14. Further communication is exchanged to perform the eID process
15. The eID process is finished and as a final step the Wallet sends a request
    to the PID Provider calling the refreshURL.
16. The PID Provider responds to the Wallet with an Authorization Response in
    response to a request sent as part of an eID process. It contains the
    authorization code.
17. The Wallet generates (and stores) a placeholder DPoP proof with a generic
  (not HSM-bound) keypair to trigger an error response from the Token endpoint
  necessary to retrieve the `dpop_nonce`.
18. The Wallet sends a Token Request to the PID Provider, containing the
    placeholder DPoP proof JWT.
19. The PID Provider generates and stores a `dpop_nonce`.
20. The PID Provider responds with the expected error "use_dpop_nonce",
    containing the `dpop_nonce` to be used from now on in the DPoP nonce header.
21. The Wallet extracts and stores the `dpop_nonce`.
22. The Wallet now prepares the actual DPoP proof JWT for `dpop_pub` including
    the `dpop_nonce` and `iat` and signs it with *dpop_priv*.
23. The Wallet sends a Token Request to the PID Provider; containing:
    - the authorization code from Authorization Response
    - the PKCE code_verifier matching the code_challenge from Authorization
      Request
    - the DPoP Header
24. The PID Provider generates and stores a fresh `dpop_nonce`.
25. The PID Provider matches the code, verifies the PKCE code_verifier to the
    previously received code_challenge and verifies the DPoP proof. It then
    generates an access token bound to the DPoP key.
26. The PID Provider sends a Token Response; containing
    - DPoP-bound access token
    - c_nonce
    - a fresh `dpop_nonce` in the DPoP nonce header
27. The Wallet generates an AES key (*pin_salt*)
    - This key will be used to generate a salt used by the PID PIN key
      derivation mechanism
28. The User enters the new PID PIN (most likely twice to ensure that the user
    has entered the intended PIN)
29. The Wallet generates the key pair (*pin_derived_eph_pub/priv*) derived from
    the PID PIN
    - This key pair is used as knowledge factor for authentication with the PID
      Provider and is discarded after every use
    - Description of the key derivation:
        - encryption of the PID PIN with an AES key bound to the device ->
          pin_secret
            - Used to generate a salt for the KDF used in the next step.
            - Could possibly be replaced by the generation & storage of a
              conventional salt (due to differences in AES in iOS/Android)
        - use of pin_secret and PID PIN in a KDF -> pin_seed
            - Generates a cryptographic secret from the PIN and the salt
              (pin_secret) for use as a seed for creating the key pair in the
              next step
        - use pin_seed to seed the EC key generation -> *pin_derived_eph_pub*
          and *pin_derived_eph_priv*
30. The Wallet signs over the nonce and the device-bound public key *device_pub*
    using the key *pin_derived_eph_priv*
    - This is a Proof of Knowledge (over the PID PIN) realized as a Proof of
      Possession
    - The nonce is `c_nonce` received in Token Response
    - The nonce and the *device_pub* key are included as JWT claims
31. The Wallet signs over the nonce and the PID PIN derived public key
    *pin_derived_eph_pub* using the key *device_priv*
    - This is a Proof of Possession over the device bound key
    - The nonce is `c_nonce` received in Token Response
    - The nonce and the *pin_derived_eph_pub* key are included as JWT claims
    - It contains audience, expiration time
32. The Wallet generates a new ephemeral keypair (*cre_eph_pub*,
    *cre_eph_priv*).
33. The Wallet creates the `credential_response_encryption` JSON object
    containing the following information:
    - a jwk containing the *cre_eph_pub*
    - the JWE alg parameter
    - the JWE enc parameter
34. The Wallet prepares the DPoP proof JWT for `dpop_pub` including the
    `dpop_nonce` and `iat` and signs it with *dpop_priv*.
35. The Wallet sends a Credential Request to the PID Provider for a newly
    defined credential format `seed_credential`; containing
    - the DPoP Header with proof
    - the DpoP-bound access token
    - PoP for *device_key* (in a `proof` parameter)
    - PoP for *pin_derived_eph_pub* containing *pin_derived_eph_pub*
    - the `credential_response_encryption` object
36. The Issuer validates the access token and DPoP proof
37. The PID Provider validates the PoPs for *pin_derived_eph* and *device_key*s
38. The PID Provider sets up the retry counter for the PID PIN  and stores it
    with *pin_derived_eph_pub* under their identifier: hash(*device_pub*)
39. The PID Provider generates the Seed Credential with eID data, *device_pub*
    and signed by *pp_priv*
40. The PID Provider creates an encrypted JWT (JWE) using the values received in
    the `credential_response_encryption` object and adds (among others) the Seed
    Credential JWT to the payload.
41. The PID Provider sends the Credential Response JWT; containing:
    - Seed Credential as JWT
42. The Wallet decrypts the Credential Response JWT using the *cre_eph_priv* and
    retrieves the Seed Credential JWT.
43. The Wallet stores the Seed Credential.

### PID Presentation

#### PID Presentation Sequence Diagram

[User Journey: PID Presentation - Authenticated Channel -
Cloud](../user_journeys/PID-AuthenticatedChannel-cloud-presentation.png)

```plantuml
@startuml

'Ensure messages are not too wide
skinparam maxMessageSize 200
skinparam wrapWidth 300

'Macro for colored [TLS] block
!function tls()
!return "<color #118888>[TLS]</color>"
!endfunction

'Align text on arrows to center
skinparam sequenceMessageAlign center

'padding between boxes
skinparam BoxPadding 100

autonumber "<b>(000)"

title PID presentation over OpenID4VP and On-the-fly PID Issuance over OpenID4VCI with SD-JWT

actor u as "User\nOpenID Holder"
participant b as "Browser App\n(same device)"
participant v [
                Relying Party
                ----
                ""Long-term Key: (//rp_pub//, //rp_priv//)""
]
participant w [
                User's EUDI Wallet Instance\
                (eID-Client)
                ----
                ""Device Key: (//device_pub//, //device_priv//)""
                ""PIN Salt: //pin_salt//""
            ]
participant i  [
                PID Provider
                (eService+eID Server)
                ----
                ""Long-term Key: (//pp_pub//, //pp_priv//)""
            ]


u --> b : browse to application
hnote over b #dfd: Screen: same_device_relying_party_start
b -> v : tls() HTTP GET <rp-website>

v -> v : generate ephemeral key pair (//rp_eph_pub//, //rp_eph_priv//)
note left: every RP in the ecosystem must always include ephemeral key in client metadata for ECDH-KA for MAC

v -> v : create OpenID4VP Authorization Request,\n sign with //rp_priv//,\n store under <request_uri>
note left: Authorization Request includes:\n- presentation_definition\n- purpose\n- state\n- nonce\n- //rp_eph_pub// with PoP bound to client_id\n- response_uri

v -> v : generate new browser session <color:#909>session_id</color> and bind the authorization request to it

v -> b : tls() HTTP 200 HTML containing wallet-link openid4vp://authorize?")\nclient_id=..&request_uri=<request_uri>\nSet-Cookie: sid=<color:#909>session_id</color>
u --> b : action to start flow/launch wallet
b -> w : launch with wallet-link openid4vp://
note right #fc7: Potential security risk: Wallet app may be spoofed by malicious app
hnote over w #dfd: Screen: launch_wallet

u --> w : unlock wallet
note right: may be moved to later point in flow or removed, see notes.
hnote over w #dfd: Screen: unlock_wallet

w -> v : tls() HTTP GET <request_uri>
note right #fc7: Potential privacy risk: RP learns existence of wallet app and potentially identifying information (e.g., headers)
v -> w : tls() HTTP 200 <JWT-Secured Authorization Request>

w -> w : validate Authorization Request JWT using //rp_pub//
note right: //rp_pub// can be retrieved from metadata using the RP client_id

'newpage

u <--> w : user consent to present PID to Relying Party for given purpose
hnote over w #dfd: Screen: consent_present_credential

w -> i : tls() HTTP POST </session_endpoint> PID issuer session id
i -> i : generate and store pid_issuer_session_id
i -> w : tls() HTTP 200 <pid_issuer_session_id>

w -> w: load PID seed credential from credential store

u <--> w: enter PID PIN
hnote over w #dfd: Screen: pid_pin

w -> w : generate key pair (//pin_derived_eph_pub//, //pin_derived_eph_priv//) from KDF(encrypt_AES(//pin_salt//, PIN), PIN)

w -> w : generate PoP for pin derived ephemeral key - sign(pid_issuer_session_id | //device_pub//)<sub>//pin_derived_eph_priv//</sub>
w -> w : generate PoP for device_key - sign(pid_issuer_session_id | //pin_derived_eph_pub//)<sub>//device_priv//</sub>

w -> w : Wallet fetches fresh wallet attestation from Wallet Backend and generates PoP with pid_issuer_session_id

group on demand PID issuance
  group Generate initial DPoP nonce
    w -> w : generate placeholder DPoP proof with generic (not HSM-bound) key pair

    w -> i : tls() HTTP POST <Token Request(DPoP Header with placeholder proof, authorization_code, PKCE code_verifier)>
    i -> i: generate and store dpop_nonce
    i -> w : tls() HTTP 400 <Bad Request (DPoP nonce Header with dpop_nonce, error: "use_dpop_nonce")>

    note left : The Wallet should check at this point, whether the Token Endpoint delivered the expected error and nonce. If not, this needs to be handled (retry or abort gracefully).
    w -> w: store dpop_nonce
  end

  w -> w: prepare DPoP proof JWT with //dpop_pub//, dpop_nonce, iat and sign with //dpop_priv//

  w -> i : tls() HTTP POST <Token Request(DPoP Header with proof, PoP for pin derived ephemeral key, PoP for device_key, seed credential, grant_type=urn:ietf:params:oauth:grant-type:seed_credential, wallet_attestation and PoP, DPoP Header)>
  note left: seed credential presentation serves as grant to get access token. new grant type (urn:ietf:params:oauth:grant-type:seed_credential) is defined in this document.
  note right: the seed credential + PoP (PoP for pin derived ephemeral key + PoP for device_key) is used to authenticate with the PID issuer and convey the user data required to generate the actual PID
  i -> i : verify wallet attestation & PoP \ncheck Wallet Provider solution status on trust list

'newpage

  i -> i: load pin retry counter and //pin_derived_eph_pub// for hash(//device_pub//)
  i -> i: check user pin retry
  note left: request would be refused in case of locked pin
  i -> i: check signatures
  note left: user pin retry counter would be increased in case of failed pin signature check, user pin would be locked after threshold is exeeded
  i -> i: store user data from seed PID in session
  i -> i: generate and store dpop_nonce
  i -> i: generate TokenResponse with DPoP-bound access token
  i -> w : tls() HTTP 200 Token Response(DPoP-nonce Header with dpop_nonce, DPoP-bound access_token, c_nonce)
  w -> w : generate credential response encryption key pair (//cre_eph_pub//, //cre_eph_priv//)
  w -> w : create credential_response_encryption object with jwk containing //cre_eph_pub//

  w -> w: prepare DPoP proof JWT with //dpop_pub//, dpop_nonce, iat and sign with //dpop_priv//

  alt #ddf B.1.1: ISO mdoc
    w -> w : calculate SessionTranscript(mDocGeneratedNonce, clientId, responseUri, nonce provided by the Verifier in the presentation request)
    w -> i : tls() Credential Request (DPoP header with proof, DPoP-bound access token, //rp_eph_pub//, credential_response_encryption object, <color blue>SessionTranscript</color>)
    note right: -//rp_eph_pub// is sent in `verifier_pub` parameter\n-SessionTranscript is sent in `session_transcript` parameter\n-no `proof`/`proofs` parameters
    i -> i : generate device key pair (//pp_eph_pub//, //pp_eph_priv//),\n create issuerAuth with //pp_eph_pub// and w/o data items\n and sign with //pp_priv//

  else #dfd B.1.2: SD-JWT VC
    w -> w : generate ephemeral key pair for KB-JWT (//kb_eph_pub//, //kb_eph_priv//) and sign nonce
    w -> i : tls() Credential Request (DPoP header with proof, DPoP-bound access token, //rp_eph_pub//, credential_response_encryption object, <color blue>//kb_eph_pub//</color>)
    note right: //rp_eph_pub// is sent in `verifier_pub` parameter
    i -> i : generate issuer key pair (//pp_eph_pub//, //pp_eph_priv//),\n create certificate for chain with //pp_eph_pub// as x5c header and sign with //pp_priv//
  end

'newpage

  i -> i : perform DH key exchange with //rp_eph_pub// and //pp_eph_priv//,\n generate shared secret k\nand derive MAC key for PID
  note over i: ECDH-MAC not specified for JOSE yet
  note over i #AAFFAA: SD-JWT is HMAC'd, not signed

  alt #ddf B.1.1: ISO mdoc
    i -> i : create deviceAuth using MAC key with eID data and SessionTranscript provided by the Wallet
    i -> i : generate encrypted credential response JWT using the values received in the credential_response_encryption object
    i --> w : tls() HTTP 200 JWT(Credential Response(<color blue>mdoc</color>))
    w -> w : decrypt credential response JWT and retrieve PID
  else #dfd B.1.2: SD-JWT VC
    i -> i : - create SD-JWT with eID data, include //kb_eph_pub// and x5c with //pp_eph_pub//, HMAC using MAC key
    i -> i : generate encrypted credential response JWT using the values received in the credential_response_encryption object
    i --> w : tls() HTTP 200 JWT(Credential Response(<color blue>SD-JWT + Disclosures</color>))
    note right: SD-JWT contains no KB-JWT
    w -> w : decrypt credential response JWT and retrieve PID
    w -> w : Assemble SD-JWT with respective disclosures and create KB-JWT payload with nonce, audience, and hash of SD-JWT and selected disclosures and sign with //kb_eph_priv//
  end

end

w -> w : create vp_token and presentation_submission
w -> w : add mDL presentation according to <presentation_definition> with <nonce> to vp_token and presentation_submission
note left #AAFFAA: Wallet may add presentations with keys under its own control as the \ncommunication channel between Relying Part and PID Provider is not E2EE

'newpage

w -> v : tls() HTTP POST encrypted <Authorization Response(presentation_submission, vp_token, state)>
v -> v : look up state in existing sessions\ncreate & store response_code for session
v --> w : tls() HTTP 200 <redirect_uri incl. response_code>

w -> b : launch browser with <redirect_uri with response_code>
hnote over w #dfd: Screen: success_redirect

b -> v : tls() HTTP GET <redirect_uri with response_code>\nCookie: sid=<color:#909>session_id</color>

v -> v : look up session with <color:#909>session_id</color> and match response_code
v -> v : perform DH key exchange with //rp_eph_priv// from session and //pp_eph_pub//,\n generate shared secret k\n derive MAC key

alt #ddf B.1.1: ISO mdoc
  v -> v : verify contents of <vp_token>:\n- verify mdoc issuerAuth/deviceAuth PID with MAC key\n- calculate and validate correct SessionTranscript
else #dfd B.1.2: SD-JWT VC
  v -> v : verify contents of <vp_token>:\n- verify SD-JWT PID with MAC key\n- verify KB-JWT with //kb_eph_pub// from SD-JWT\n- validate nonce and audience from KB-JWT
end

v --> b : tls() HTTP 200 <HTML with continued UX flow>
hnote over b #dfd: Screen: same_device_relying_party_identified

@enduml
```

<!-- PDF-show
\elandscape
-->

#### PID Presentation Step-by-Step Description

Note: While certain assumptions about session management of the Relaying Party
are made here, the concrete implementation is considered out of scope for this
document. The usual security considerations for web session management apply.

1. User browses to Relying Party (RP) website
2. Browser app on the user's device opens the RP website
3. RP generates a key pair to be used for ECDH key agreement for SD-JWT HMAC'ing
4. RP generates an OpenID4VP Authorization Request and stores it under a
   `request_uri` (e.g., `https://rp.example.com/oidc/request/1234`);
   - The request is bound to the user's browser session
   - It is signed using a key bound to the RP's metadata that can be retrieved
     using the RP's client_id
   - It contains the ephemeral key for ECDH key agreement for SD-JWT HMAC'ing
   - It contains RP's nonce and state
   - It contains the RP's response_uri endpoint for sending the Authorization
     Response over POST
5. RP generates a new browser session and binds the generated Authorization
   Request to it
6. RP returns a HTML page to the browser containing a link to the wallet app
   (e.g.,
   `openid4vp://authorize?client_id=..&request_uri=https://rp.example.com/oidc/request/1234`);
   a cookie with the browser session id is set
7. The user clicks on the link
8. The RP website navigates to the custom scheme link to launch the wallet app
9. The user unlocks the wallet app (see notes below)
10. The wallet app retrieves the Authorization Request from the RP website
    (e.g., `https://rp.example.com/oidc/request/1234`)
11. The wallet app receives the Authorization Request
12. The wallet app validates the Authorization Request using the RP's public key
    - Was the signature valid and the key bound to the RP's metadata?
    - **Security:** This ensures that the Authorization Request was not tampered
      with; it does not ensure that the party that sent the Authorization
      Request is the RP.
13. The Wallet displays information about the identity of the Relying Party and
    the purpose, the user gives consent to present the PID.
14. The Wallet requests a fresh PID issuer session id from the PID Provider
    (pid_issuer_session_id)
15. The PID Provider generates a fresh session id linked to the session
16. The PID Provider returns the PID issuer session id to the Wallet
17. The Wallet loads the PID seed credential from the credential store
18. The User enters the PID PIN
19. The Wallet generates the key pair (*pin_derived_eph_pub/priv*) derived from
    the PID PIN
    - See PID Seed-Credential Issuance Steps 20 to 22 for a detailed description
      of the authentication process
20. The Wallet signs over the PID issuer session id and the device-bound public
    key *device_pub* using the key *pin_derived_eph_priv*
21. The Wallet signs over the PID issuer session id and the PID PIN derived
    public key *pin_derived_eph_pub* using the key *device_priv*
22. The Wallet fetches fresh wallet attestation from the Wallet Provider
    backend, generates proof of possession PoP (incl. PID issuer session id)
23. The Wallet generates (and stores) a placeholder DPoP proof with a generic
  (not HSM-bound) keypair to trigger an error response from the Token endpoint
  necessary to retrieve the `dpop_nonce`.
24. The Wallet sends a Token Request to the PID Provider, containing the
    placeholder DPoP proof JWT.
25. The PID Provider generates and stores a `dpop_nonce`.
26. The PID Provider responds with the expected error "use_dpop_nonce",
    containing the `dpop_nonce` to be used from now on in the DPoP nonce header.
27. The Wallet extracts and stores the `dpop_nonce`.
28. The Wallet now prepares the actual DPoP proof JWT for `dpop_pub` including
    the `dpop_nonce` and `iat` signed with *dpop_priv*.
29. The wallet sends a Token Request to the PID Provider; containing
    - PoP for *pin_derived_eph* key
    - PoP for *device_key*
    - Seed Credential (bound to *device_pub*)
    - Wallet Attestation + PoP (incl. pid_provider_session_id)
    - a DPoP key
    - grant_type (urn:ietf:params:oauth:grant-type:seed_credential)
        - seed credential + Wallet attestation PoP (both bound to the same key)
          - PoP for *pin_derived_eph* and *device_key* serves as grant to get
          access token. New grant type
          (urn:ietf:params:oauth:grant-type:seed_credential) is defined in this
          document.
30. The PID Provider verifies the wallet attestation and its proof of possession
    and validates the certification status of the Wallet Solution on a trust
    list
31. The PID Provider loads the retry counter and *pin_derived_eph_pub* with the
    identifier hash(*device_pub*)
32. The PID Provider checks the users PID PIN retry counter
    - If the PIN retry counter has exceeded the defined maximum value, the
      request is rejected
33. The PID Provider validates the PoP for *pin_derived_eph* and *device_key*
34. The PID Provider stores the user data from the PID seed credential in the
    session
35. The PID Provider generates and stores a `dpop_nonce`.
36. The PID Provider generates a TokenResponse with a DPoP-bound access token
37. The PID Provider sends a Token Response; containing
    - DPoP-bound access token
    - a c_nonce
    - a fresh `dpop_nonce` in the DPoP nonce header
38. The Wallet generates a new ephemeral keypair (*cre_eph_pub*,
    *cre_eph_priv*).
39. The Wallet creates the `credential_response_encryption` JSON object
    containing the following information:
    - a jwk containing the *cre_eph_pub*
    - the JWE alg parameter
    - the JWE enc parameter
40. The Wallet prepares the DPoP proof JWT for `dpop_pub` including the
    `dpop_nonce` and `iat` signed *dpop_priv*.
41. **(mdoc)** The Wallet calculates the SessionTranscript according to
    ISO-18013-7 Annex B.4.4 from mDocGeneratedNonce, client_id, responseUri,
    nonce (provided by the Verifier in the presentation request). The final
    result is a SHA-256 hash, thus not revealing the client_id and ResponseUri
    to the PID Provider.
42. **(mdoc)** The Wallet sends a Credential Request; containing
    - the DPoP-bound access token
    - SessionTranscript(mdocGeneratedNonce, client_id, responseUri, nonce)
    - the ephemeral RP key *rp_eph_pub* from the RP's Authorization Request
    - the `credential_response_encryption` object
    - it does not contain a "proof"
43. **(mdoc)** The PID Provider generate an ephemeral DeviceKey pair
    (*pp_eph_pub*,*pp_eph_priv*) and creates the mdoc issuerAuth (MSO) with the
    public part of DeviceKey and without the IssuerSignedItems and signs it with
    *pp_priv*.
44. **(SD-JWT)** The Wallet generates an ephemeral key pair for the KB-JWT
    (*kb_eph_pub*, *kb_eph_priv*) and signs the nonce
45. **(SD-JWT)** The wallet app sends the Credential Request to the PID
    Provider; containing
    - the DPoP-bound access token
    - the ephemeral RP key *rp_eph_pub* from the RP's authorization request
    - the `credential_response_encryption` object
    - the ephemeral KB-JWT key *kb_eph_pub*
46. **(SD-JWT)** The PID Provider generates the ephemeral issuer key pair
    (*pp_eph_pub*, *pp_eph_priv*) and creates a certificate for the chain with
    *pp_eph_pub* as x5c header and signs it with *pp_priv*.
47. The PID Provider performs DH key exchange with the ephemeral RP public key
    *rp_eph_pub* and the ephemeral issuer private key *pp_eph_priv*, generates a
    shared secret k and derives a MAC key for the PID.
48. **(mdoc)** The PID Provider creates the mdoc deviceAuth (using the MAC key)
    containing
    - the user claims
    - the OpenID4VP SessionTranscript(mdocGeneratedNonce, client_id,
      responseUri, nonce)
    - SessionTranscript used by the PID Provider is generated by the Wallet and
      is passed to the PID Provider in step 32, so PID Provider does not need to
      be aware of the values used to generate SessionTranscript
49. **(mdoc)** The PID Provider creates an encrypted JWT (JWE) using the values
    received in the `credential_response_encryption` object and adds (among
    others) the PID credential to the payload.
50. **(mdoc)** The PID Provider sends the Credential Response JWT; containing:
    - PID as mdoc
51. **(mdoc)** The Wallet decrypts the Credential Response JWT using the
    *cre_eph_priv* and retrieves the PID.
52. **(SD-JWT)** The PID Provider creates the issuer-signed part of the SD-JWT
    (using the MAC key) containing
    - eID as the user claims
    - *kb_eph_pub* as cnf claim
53. **(SD-JWT)** The PID Provider creates an encrypted JWT (JWE) using the
    values received in the `credential_response_encryption` object and adds
    (among others) the PID credential to the payload.
54. **(SD-JWT)** The PID Provider sends the Credential Response JWT; containing:
    - PID as SD-JWT VC
    - Disclosures
55. **(SD-JWT)** The Wallet decrypts the Credential Response JWT using the
    *cre_eph_priv* and retrieves the PID.
56. **(SD-JWT)** The Wallet assembles the SD-JWT with the selected disclosures
    and creates the header and payload for the KB-JWT from audience, nonce, and
    the hash of SD-JWT and selected disclosures and signs it with its generated
    *kb_eph_priv*. The Wallet appends the KB-JWT to the SD-JWT + Disclosures.
57. The wallet app creates a VP token and a presentation submission from the
    received SD-JWT PID.
58. Optional: The wallet app can add further presentations with keys under its
    own control as the communication channel between Relying Party and PID
    Provider is not E2EE
59. The wallet app sends the VP token and presentation submission to the RP
    (encrypted to the RP's public key *rp_eph_pub*).
60. The RP finds a session with the state and generates a response_code for this
    session
61. The RP returns the redirect_uri with the response_code to the wallet app
62. The wallet app launches the browser with the redirect_uri and response_code.
63. The browser sends the redirect_uri and response code to the RP, attaching
    the browser session id as a cookie.
64. The RP looks up whether there exists a session with the session id from the
    cookie and a matching response_code
65. Using the data from the session the RP performs DH key exchange with the PID
    Provider's public key, generates a shared secret k and derives a MAC key.
66. **(mdoc)** The RP verifies the PID in the VP token with the MAC key and
    verifies the SessionTranscript.
67. **(SD-JWT)** The RP verifies the SD-JWT PID in the VP token with the MAC
    key, verifies the KB-JWT using the *kb_eph_pub* in the SD-JWT, and verifies
    the nonce and audience in the KB-JWT
68. The RP considers the user to be identified in the session context and
    continues the UX flow.

## Extensions to the Protocols

This section defines extensions to the protocols required to implement this flow
(Option B').

In this document, the term `RP` has been used, but this since this section is an
extension to an OpenID4VCI protocol, a term from that specification is being
used, which is `verifier`.

### Issuer Session Endpoint (at the PID Provider)

Note that this extension is the same across multiple flows.

This endpoint is used by the Wallet to obtain `session_id` from the PID Provider
that is used to bind PoPs to the session and prove their freshness. Support for
this endpoint is REQUIRED.

To fetch the `session_id`, the Wallet MUST send an HTTP request using the POST
method and the `application/json` media type. The PID Provider MUST return the
HTTP Status Code 200 and a `session_id` parameter defined below.

- `session_id`: REQUIRED. String that is a unique session identifier, chosen as
  a cryptographically random nonce with at least 128 bits of entropy.

Communication with the Session Endpoint MUST utilize TLS.

Below is a non-normative example of a request to a Session Endpoint:

```http
POST /session_endpoint HTTP/1.1
Host: server.example.com
Content-Type: application/json

```

Below is a non-normative example of a response from a Session Endpoint:

```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "session_id": "iOiJSUzI1NiIsInR"
}
```

### OpenID4VCI Credential Issuer Metadata

Note that this extension is the same across multiple flows.

This document defines the following additional Credential Issuer Metadata
parameters:

- `session_endpoint`: REQUIRED. URL of the Credential Issuer's Session Endpoint,
  as defined in a previous section. This URL MUST use the `https` scheme and MAY
  contain port, path, and query parameter components.

### OpenID4VCI Credential Request for Seed Credential Issuance

This section defines a Credential Format Profile for a Seed Credential.

The Credential Format identifier is `seed_credential`.

The following Credential Format specific parameter must be included in the
Credential Request to issue a seed credential of this format:

- `pin_derived_eph_key_pop`: A string containing a JWT which is generated by the
  Wallet signing over the `nonce` (`c_nonce` received in Token Response) and the
  device-bound public key `device_key` parameters using the
  `pin_derived_eph_priv` key. A PIN-derived ephemeral public key that is needed
  to validate the signature on this JWT must be included in the `jwk` header
  parameter. The JWT header must contain a `typ` key with the value being
  `pin_derived_eph_pub_pop`. The JWT payload must contain an `aud` claim whose
  value is equal to the PID Provider's Credential Issuer Identifier.

Either a `proof` parameter or a `proofs` parameter containing one proof must be
present. Proof type must be `jwt`. A proof MUST be a JWT which is generated by
the Wallet signing over the `nonce` (`c_nonce` received in Token Response) and
the `pin_derived_eph_pub` using the `device_key`. A `device_pub` key that is
needed to validate the signature on this JWT must be included in the `jwk`
Header parameter.

Below is a non-normative example of a Credential Request during Seed Credential
issuance:

```json
POST /credential HTTP/1.1
Host: server.example.com
Content-Type: application/json
Authorization: DPoP czZCaGRSa3F0MzpnWDFmQmF0M2JW
DPoP: ey…

{
  "format": "seed_credential",
  "pin_derived_eph_key_pop": "eyJ0eX...Lh1WlA",
  "proof": {
    "proof_type": "jwt",
    "jwt": "eyJraW...KPxgihac0aW9E"
  },
  "credential_response_encryption": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "Q71r9rep9wGjorxnnTrxzrN6CxJTc_0vucTkAQSFSzM",
      "y": "jh7gtLKEMH2PQ6hz2USSvsMAvhyF90OBScZ9KJ-1Z-o"
    },
    "alg": "ECDH-ES",
    "enc": "A256GCM"
  }
}
```

Below is a non-normative example of a JWT sent in a `pin_derived_eph_key_pop`
parameter used as a PoP for pin derived ephemeral key during Seed Credential
issuance:

```json
{
  "alg": "...",
  "typ": "pin_derived_eph_key_pop",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "bPP7f...gW_ao",
    "y": "38_Lg...VUCfW"
  }
}.
{
  "nonce": "123456",
  "aud": "https://pid-issuer.example.com",
  "device_key": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "...",
      "y": "..."
    }
  }
}.[signature by the pin derived ephemeral pub key]
```

The `jwk` claim contains the public key of a PIN-derived ephemeral key pair.

Below is a non-normative example of a JWT used as a proof during Seed Credential
issuance, which is a PoP for `device_key`:

```json
{
  "alg": "...",
  "typ": "openid4vci-proof+jwt",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "...",
    "y": "..."
  }
}.
{
  "nonce": "123456",
  "pin_derived_eph_pub": {
    "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "V03QP...LHN53",
    "y": "xjilK...i0_tT"
    }
  },
  "aud": "https://pid-issuer.example.com",
  "iat": 1701960444
}.[signature by the device_key]
```

Here, the `jwk` claim contains a public key of a device key pair.

The payload contains `aud` and `iat` claims and the header contains `alg` and
`typ` claims, which is a requirement for `jwt` proof type as defined in
OpenID4VCI specification.

Below is a non-normative example of a Credential Response JWT (JWE) during the
during Seed Credential issuance::

```json
HTTP/1.1 200 OK
Content-Type: application/jwt
Cache-Control: no-store

{
  "epk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "GNIg9Vdq4gytYyVsANPZGtS_eKWjjWJQYDGaM1olFZI",
    "y": "Vjk0mlZD_CwXrtIJkPH-ZzdwqJp3QBRVp83pEeQUDC0"
  },
  "enc": "A256GCM",
  "alg": "ECDH-ES"
}..
3tQxSrYcfmbEWw-Y.
yp9e0Kh0THo498bg5nnUIpkS-CwxlS8i6G9RfZBOzUOeohaVnAPAWHY.
PhU-FNmCt_ZZPzj5RgPNmQ
```

The decrypted payload of the Credential Response JWT example results in the
following structure:

```json
{
  "credential": "<Seed Credential JWT>"
}
```

### OpenID4VCI Token Request for PID Issuance using Seed Credential

A new grant type `urn:ietf:params:oauth:grant-type:seed_credential` is defined
by this document.

The following parameters must be included in the Token Request:

- `seed_credential`: A string containing a JWT that is a previously issued seed
  credential.
- `pin_derived_eph_pub_pop`: A string containing a JWT which is generated by the
  Wallet signing over the `pid_issuer_session_id` and the device-bound public
  key `device_key` parameters using the `pin_derived_eph_priv` key. A
  PIN-derived ephemeral public key that is needed to validate the signature on
  this JWT must be included in the `jwk` header parameter. There must be a JWT
  header parameter `typ` with the value being `pin_derived_eph_pub_pop`. The JWT
  payload must contain an `aud` claim whose value is equal to the PID Provider's
  Credential Issuer Identifier.
- `device_key_pop`: A string containing a JWT which is generated by the Wallet
  signing over the `pid_issuer_session_id` and the device-bound public key
  `pin_derived_eph_pub` parameters using the `device_priv` key. A device public
  key that is needed to validate the signature on this JWT must be included in
  the `jwk` header parameter. There must be a JWT header parameter `typ` with
  the value being `device_key_pop`. The JWT payload must contain an `aud` claim
  whose value is equal to the PID Provider's Credential Issuer Identifier.

Below is a non-normative example of a Token Request during the PID issuance
(including DPoP and wallet attestation):

```http
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: ey...
OAuth-Client-Attestation: ey...
OAuth-Client-Attestation-PoP: ey...

grant_type=urn:ietf:params:oauth:grant-type:seed_credential
&seed_credential=ey...
&pin_derived_eph_key_pop=ey...
&device_key_pop=ey...
```

Note: `client_id` will be present instead of OAuth-Client-Attestation and
OAuth-Client-Attestation-PoP headers used to pass wallet attestation, when
wallet attestation is not used.

Below is a non-normative example of a JWT sent in a `pin_derived_eph_key_pop`
parameter used as a PoP for pin derived ephemeral key during PID issuance:

```json
{
  "alg": "...",
  "typ": "pin_derived_eph_key_pop",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "bPP7f...gW_ao",
    "y": "38_Lg...VUCfW"
  }
}.
{
  "pid_issuer_session_id": "123456",
  "aud": "https://pid-issuer.example.com",
  "device_key": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "...",
      "y": "..."
    }
  }
}.[signature by the pin derived ephemeral pub key]
```

The `jwk` claim contains the public key of a PIN-derived ephemeral key pair.

Below is a non-normative example of a JWT used as a proof during PID issuance,
which is a PoP for `device_key`:

```json
{
  "alg": "...",
  "typ": "device_key_pop",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "...",
    "y": "..."
  }
}.
{
  "pid_issuer_session_id": "123456",
  "aud": "https://pid-issuer.example.com",
  "pin_derived_eph_pub": {
    "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "V03QP...LHN53",
    "y": "xjilK...i0_tT"
    }
  },
}.[signature by the device_key]
```

Here, the `jwk` claim contains a public key of a device key pair.

### OpenID4VCI Credential Request and Response for PID Issuance in mdoc Credential Format using Authenticated Channel

Note that this section is the same as in Option B.

Credential Format identifier is `mso_mdoc_authenticated_channel`.

The following parameters are defined in addition to those defined for the
Credential Format `mso_mdoc` in Annex A.2 of OpenId4VCI:

- `session_transcript`: REQUIRED. String that is a base64url encoded
  SessionTranscriptBytes as defined in Section 9.1.5.1 of ISO 18013-5.
- `verifier_pub`: REQUIRED. A JSON object as defined in Section 2 of RFC7591. It
  contains the ephemeral RP key *rp_eph_pub* from the RP's Authorization
  Request.

`proof` or `proofs` parameter MUST NOT be present.

DPoP-bound Access token MUST be present.

`credential_response_encryption` parameter MUST be present. Note: The wallet can
find out about the supported cryptographic algorithms by using the Issuer's
metadata parameter `credential_response_encryption`.

Below is a non-normative example of a Credential Request during the PID issuance
in ISO mso Credential Format over Authenticated Channel:

```json
POST /credential HTTP/1.1
Host: server.example.com
Content-Type: application/json
Authorization: DPoP czZCaGRSa3F0MzpnWDFmQmF0M2JW
DPoP: ey…

{
  "format": "mso_mdoc_authenticated_channel",
  "doctype": "org.iso.18013.5.1.mDL",
  "session_transcript": "...",
  "verifier_pub": {
    "kty": "EC",
    "crv": "P-256",
    "x": "aPPK-...2-Drn",
    "y": "FqJqG...ksKHp"
  },
  "credential_response_encryption": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "1SptQyCUQiQD3dBcVHTclxRtcqhZlF1rIKcBR-i_WK4",
      "y": "8ayoQrh52zNuRQx8Q0gpmCpOjzbH397mOsaSi8X10c4"
    },
    "alg": "ECDH-ES",
    "enc": "A256GCM"
  }
}
```

`credential` parameter in the Credential Response MUST contain a
base64url-encoded `Document` which contains `IssuerSigned` and the
`DeviceSigned` parameters defined in section 8.3.2.1.2.2 of 18013-5.

The Device key included in the `IssuerSigned` and used to secure `DeviceSigned`
is generated by the PID Provider, and not by the Wallet as defined in ISO
18013-5.

SessionTranscript used by the PID Provider when calculating `DeviceSigned` is
calculated by the Wallet. Therefore, there is no need for the PID Provider to
know the specific values of `mdocGeneratedNonce`, `client_id`, `responseUri`,
and `nonce` parameters used for SessionTranscript calculation by the Wallet.
Moreover, there is also no way for the PID Provider to reconstruct these values,
as the SessionTranscript is hashed and contains random values chosen by the
wallet (i.e. `mdocGeneratedNonce`).

Below is a non-normative example of a Credential Response JWT (JWE) during the
PID issuance in mso Credential Format over Authenticated Channel:

```json
HTTP/1.1 200 OK
Content-Type: application/jwt
Cache-Control: no-store

{
  "epk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "VJUVl-ZqLKzzncZ4Gs_nJfcqY_YBHPkGVN0sRSlF-3s",
    "y": "y4maAWKte676d0wL6um-8wAUJ9pW-mlc528BFeiXn2Y"
  },
  "enc": "A256GCM",
  "alg": "ECDH-ES"
}..
nLuW9PwrGl76pjTy.
nH_XE2LJ2u-N0o8M-tanqoYhJr7hbjo.
3uNrPqJazT9ZSf54sk1Ueg
```

The decrypted payload of the Credential Response JWT example results in the
following structure:

```json
{
  "credential": "..."
}
```

### OpenID4VCI Credential Request and Response for PID Issuance in SD-JWT Credential Format using Authenticated Channel

Note that this section is the same as in Option B.

The following parameter is defined in addition to those defined for the
Credential Format `vc+sd-jwt` in Annex A.3 of OpenId4VCI:

- `verifier_pub`: REQUIRED. A JSON object as defined in Section 2 of RFC7591. It
  contains the ephemeral RP key *rp_eph_pub* from the RP's Authorization
  Request.

New Credential Format identifier is not defined PID Issuance in SD-JWT
Credential Format using Authenticated Channel, because the issued Credential in
the Credential Response is SD-JWT, which is the same as the one defined in Annex
A.3 of OpenId4VCI. Since during PID Issuance in SD-JWT Credential Format using
Authenticated Channel, not just `IssuerSigned`, but also `DeviceSigned` is
returned in the Credential Response as part of the `Document` structure as
defined above, it is a significant deviation that necessitated the definition of
a new Credential Format identifier `mso_mdoc_authenticated_channel`.

`credential_response_encryption` parameter MUST be present. Note: The wallet can
find out about the supported cryptographic algorithms for the credential
response encryption by using the Issuer's metadata parameter
`credential_response_encryption`.

Below is a non-normative example of a Credential Request during the PID issuance
in IETF SD-JWT VC Credential Format over Authenticated Channel: Note: The wallet
can find out about the supported cryptographic algorithms by using the Issuer's
metadata parameter `credential_signing_alg_values_supported`.

```json
POST /credential HTTP/1.1
Host: server.example.com
Content-Type: application/json
Authorization: DPoP czZCaGRSa3F0MzpnWDFmQmF0M2JW
DPoP: ey…

{
  "format": "vc+sd-jwt",
  "vct": "SD_JWT_VC_example",
  "proof": {
    "proof_type": "jwt",
    "jwt": "eyJ0e...h1WlA"
  },
  "verifier_pub": {
    "kty": "EC",
    "crv": "P-256",
    "x": "aPPK-...2-Drn",
    "y": "FqJqG...ksKHp"
  },
  "credential_response_encryption": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "1SptQyCUQiQD3dBcVHTclxRtcqhZlF1rIKcBR-i_WK4",
      "y": "8ayoQrh52zNuRQx8Q0gpmCpOjzbH397mOsaSi8X10c4"
    },
    "alg": "ECDH-ES",
    "enc": "A256GCM"
  }
}
```

## Implementation Considerations

- The JWA to use the x5c in the SD-JWT and perform ECDH key agreement and derive
  the MAC key is to be defined.

## Usability Considerations

### Initialization

- The wallet can only be used after successful initialization

### Issuance

- Credential catalogue should inform users in advance of what is required for
  the successful issuance of the PID and what steps follow
    - For reasons of transparency and to increase trust, PID Provider should
    provide sufficient information (metadata) for the consent screen. This
    allows users to learn everything relevant e.g. about the PID Provider itself
- eID process is integrated in Wallet. No context switch to the AusweisApp is
  requiredPhysical ID card is required for issuing the PID seed credential
- Online-Ausweisfunktion must be activated
- eID PIN must be set by the user (replacement of the Transport PIN) and be
  known to them so that they can successfully confirm the process
- User can have a PID seed credential derived from the eID on several end
  devices at the same time
- A PID-specific PIN must be set. The distinction between eID PIN and PID PIN is
  certainly not easy for users and must be communicated accordingly
- In addition to the PID-specific PIN, several PINs will probably be required to
  use the wallet (especially for LoA High Credentials). This will also require
  multiple error counters. This can lead to user confusion, unnecessary
  complexity and ultimately friction

### Presentation

- The device must be online for the PID presentation
- Relying Party should inform users in advance of what is required for the
  process to be completed successfully and what steps follow
- It needs to be clarified whether the wallet app needs to be unlocked in this
  flow and how this should be implemented.
- For reasons of transparency and to increase trust, Relying Parties should
  provide sufficient information (metadata) for the consent screen. This allows
  users to learn everything relevant e.g. about the relying party itself,
  privacy and data retention
- The user's data values for the requested attributes can be displayed on the
  consent screen
- The user only needs to enter the PID PIN for each PID presentation
- Physical ID card is not required for PID presentation
- It must be ensured that users return to the correct tab in the correct browser
  in order to continue the process or know how to get there manually if
  necessary (especially for iOS devices, if the process was not started in the
  default browser)

## Security Considerations

- It is to be discussed whether the setting of the PID PIN should be more
  closely linked to the eID process. In this case, the public keys and PoPs
  required for the PID PIN check could be transferred as an additional attribute
  in the eID process.
- In Step 8 of the presentation, a malicious app may spoof the wallet app by
  registering to the same custom URL scheme; an attacker may
    - **on the attacker's own device:** Capture the request and replay it to a
    victim on another device, thus having the victim identify itself in a
    context of the attacker (**Relaying Attack breaking Identification
    Context**); or
    - **on the victim's device:** Capture the request and spoof the whole
    identification process or parts of it (**Wallet App Spoofing**).
- In Step 10 of the presentation: An attacker acting as an RP can forward a
  request from a different RP.
    - As long as the request remains unchanged, we're in the **Relaying Attack
    breaking Identification Context**
    - If the attacker changes anything in the request, this will break the
    signature. The attacker could otherwise attempt to
        - insert the attacker's own ephemeral key, leading to an SD-JWT artifact
      that could be used in a different flow between the attacker and some other
      RP.
        - modify state or nonce or other data. **Q:** Any useful attacks resulting
      from this?
- In Step 46 of the presentation: The RP must not consider the user identified
  at this point; it is important to have the browser redirect in the later
  steps.
- In Step 11 and onward of the PID Seed Credential issuance: Security of PID
  Provider Interface:
    - Are additional steps required to protect the interface to the PID Provider?
    - What exactly is the transaction binding?
    - How is the eID process tied to the process at the PID Provider?

## Privacy Considerations

- Due to the differences in the selective disclosure process of SD-JWT VC and
  mDoc, it is only possible with the SD-JWT variant to prevent the PID Provider
  from knowing which attributes are to be disclosed to a relying party.
- An initiating step before the authorization request (Step 10 of the
  presentation) that is performed without the user's interaction might leak
  information about the user's device to the RP (**Initial Request Privacy
  Leak**). For example:
    - the fact that the wallet app is installed,
    - the fact which wallet app is installed,
    - some metadata about the wallet app contained in request headers (e.g.,
    version, language, etc.),
    - network information if the browser uses a VPN but the wallet app does not
- Unlinkability: Each Relying Party sees a new credential for each use of the
  flow. Only ephemeral keys are used. Unless the eID data itself enables
  linkability, there is no information enabling linkablility between different
  uses of the flow.