Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Multi RP Credentials/Authentication capability #308

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0833045
first sketch
tlodderstedt Nov 5, 2024
141e359
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Nov 14, 2024
5c69e3e
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Nov 14, 2024
54a1672
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Nov 14, 2024
71268d6
fixed typo
tlodderstedt Nov 14, 2024
43521e1
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Nov 26, 2024
79a01ee
recovered JWS Compact Serialization
tlodderstedt Dec 6, 2024
4c7867d
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 10, 2025
1ef2c5a
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 10, 2025
80c8ffe
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 10, 2025
b8c1449
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 10, 2025
e2fe62e
added IANA registration of JOSE header parameters
tlodderstedt Jan 10, 2025
7c2ec1c
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 10, 2025
58e3ffa
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 10, 2025
ed6c840
Merge branch 'main' into multiple-rp-credentials
Sakurann Jan 14, 2025
1f50e80
fixed copy and paste
tlodderstedt Jan 14, 2025
f912e13
Merge branch 'multiple-rp-credentials' of https://github.com/openid/O…
tlodderstedt Jan 14, 2025
7e2b268
removed kid in example
tlodderstedt Jan 14, 2025
72a31f8
added entry to document history
tlodderstedt Jan 14, 2025
4f13bd4
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 14, 2025
c9de4d1
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 14, 2025
9dbbc4e
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 14, 2025
20964b0
Merge branch 'multiple-rp-credentials' of https://github.com/openid/O…
tlodderstedt Jan 14, 2025
a49eb50
moved client_metadata back into request
tlodderstedt Jan 14, 2025
f6dea92
removed client_metadata JOSE header registration
tlodderstedt Jan 14, 2025
e32cecf
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 23, 2025
d8bb9ff
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 23, 2025
d7a5048
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 23, 2025
339e966
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 23, 2025
1a2f830
Update openid-4-verifiable-presentations-1_0.md
tlodderstedt Jan 23, 2025
6d93c66
modified example to match change re enc key
tlodderstedt Jan 27, 2025
9d7321c
Merge branch 'multiple-rp-credentials' of https://github.com/openid/O…
tlodderstedt Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 1 addition & 22 deletions examples/digital_credentials_api/signed_request_payload.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,10 @@
{
"client_id": "https://client.example.org",
"expected_origins": [
"https://origin1.example.com",
"https://origin2.example.com"
],
"response_type": "vp_token",
"response_mode": "dc_api.jwt",
"nonce": "n-0S6_WzA2Mj",
"client_metadata": {
"vp_formats": {
"dc+sd-jwt": {
"sd-jwt_alg_values": [ "PS256" ],
"kb-jwt_alg_values": [ "PS256" ]
}
},
"jwks": {
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use": "enc",
"kid": "1"
}
]
}
},
"presentation_definition": {...}
"dcql_query": {...}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were the client_id, client_metadata, and jwks deleted? This change seems unrelated to the purpose of this PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed related to this PR, as this data elements are RP specific. Consequently, the PR moves them into the RP credential specific elements of the request.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should discuss where the client_id, client_metadata, and jwks claims should go when using the Compact Serialization. These would normally be claims - not header parameters.

I understand the reasoning for making them header parameters when using the JSON Serialization, but in my view, that's not the normal case, and we should make the normal case natural.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

client_id, client_metadata, and jwks are request parameters when using the Compact Serialization. see examples/digital_credentials_api/signed_request_payload_compact.json

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"expected_origins": [
"https://origin1.example.com",
"https://origin2.example.com"
],
"client_id": "x509_san_dns:rp.example.com",
"client_metadata": {
"jwks": {
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use": "enc",
"kid": "1"
}
]
}
},
"response_type": "vp_token",
"response_mode": "w3c_dc_api.jwt",
"nonce": "n-0S6_WzA2Mj",
"dcql_query": {...}
}
68 changes: 64 additions & 4 deletions openid-4-verifiable-presentations-1_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -2013,19 +2013,70 @@ The Verifier MAY send all the OpenID4VP request parameters as members in the req

The Verifier MAY send a signed request, for example, when identification and authentication of the Verifier is required.

The signed request allows the Wallet to authenticate the Verifier using one or more trust framework(s) in addition to the Web PKI utilized by the browser. An example of such a trust framework is the Verifier (RP) management infrastructure set up in the context of the eIDAS regulation in the European Union, in which case, the Wallet can no longer rely only on the web origin of the Verifier. This web origin MAY still be used to further strengthen the security of the flow. The external trust framework could, for example, map the Client Identifier to registered web origins.

The signed Request Object MAY contain all the parameters listed in (#dc_api_request), except `request`.

Below is a non-normative example of such a request sent over the Digital Credentials API (DC API):
Verifiers can format signed Requests either using JWS Compact Serialization or JWS Serialization [@!RFC7515]).
tlodderstedt marked this conversation as resolved.
Show resolved Hide resolved

#### JWS Compact Serialization

In case of the JWS Compact Serialization, all request parameters are encoded in a request object as defined in (#vp_token_request) and the JWS object is used as the value of the `request` claim in the `data` element of the API call. This is illustated in the following example.
tlodderstedt marked this conversation as resolved.
Show resolved Hide resolved

```js
{ request: "eyJhbGciOiJF..." }
```

This is an example of the payload of a signed OpenID4VP request used with the DC API:
This is an example of the payload of a signed OpenID4VP request used with the W3C Digital Credentials API in conjunction with JWS Compact Serialization:

<{{examples/digital_credentials_api/signed_request_payload_compact.json}}

#### JWS JSON Serialization

The JWS JSON Serialization [@!RFC7515]) allows the Verifier to use multiple Client Identifiers and corresponding key material and metadata to protect the same request. This serves use cases where the Verifier requests credentials belonging to different trust frameworks and, therefore, needs to authenticate in the context of those trust frameworks.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The JWS JSON Serialization [@!RFC7515]) allows the Verifier to use multiple Client Identifiers and corresponding key material and metadata to protect the same request. This serves use cases where the Verifier requests credentials belonging to different trust frameworks and, therefore, needs to authenticate in the context of those trust frameworks.
Using JWS JSON Serialization [@!RFC7515]) to send the Request allows the Verifier to use multiple Client Identifiers and corresponding key material and metadata to protect the same request. This serves use cases where the Verifier requests credentials belonging to different trust frameworks and, therefore, needs to authenticate in the context of those trust frameworks.
This is achieved by passing multiple signatures of the same paylod in the protected header.

this is just a suggestion, but please provide an overview of the solution here. otherwise there is a jump between this short description and the technical details below..

tlodderstedt marked this conversation as resolved.
Show resolved Hide resolved

In this case, the following request parameters MUST be present in the protected header of the respective `signature` object in the `signatures` array defined in [@!RFC7515, section 7.2.1]:

* `client_id`

All other request parameters MUST be present in the `payload` element of the JWS object.

Below is a non-normative example of such a request:

```js
{
"payload": "eyAiaXNzIjogImh0dHBzOi8...NzY4Mzc4MzYiIF0gfQ",
"signatures": [
{
"protected": "eyJhbGciOiAiRVMyNT..MiLCJraWQiOiAiMSJ9XX19fQ",
"signature": "PFwem0Ajp2Sag...T2z784h8TQqgTR9tXcif0jw"
},
{
"protected": "eyJhbGciOiAiRVMyNTY...tpZCI6ICIxIn1dfX19",
"signature": "irgtXbJGwE2wN4Lc...2TvUodsE0vaC-NXpB9G39cMXZ9A"
}
]
}
```

Every object in the `signatures` structure contains the parameters and the signature specific to a particular Client Identifier. The signature is calculated as specified in section 5.1 of [@!RFC7515].

This is an example of a protected header:
tlodderstedt marked this conversation as resolved.
Show resolved Hide resolved

```
{
"alg": "ES256",
"x5c": [
"MIICOjCCAeG...djzH7lA==",
"MIICLTCCAdS...koAmhWVKe"
],
"client_id": "x509_san_dns:rp.example.com"
}
Comment on lines +2069 to +2076
Copy link
Collaborator

@Sakurann Sakurann Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specific proposal for disambiguating credential requested and credential_id

Suggested change
{
"alg": "ES256",
"x5c": [
"MIICOjCCAeG...djzH7lA==",
"MIICLTCCAdS...koAmhWVKe"
],
"client_id": "x509_san_dns:rp.example.com"
}
{
"alg": "ES256",
"x5c": [
"MIICOjCCAeG...djzH7lA==",
"MIICLTCCAdS...koAmhWVKe"
],
"client_id": "x509_san_dns:rp.example.com",
"credential_ids": [ <Array of strings each referencing a Credential requested by the Verifier> ]
}

Copy link
Collaborator

@Sakurann Sakurann Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

credential_ids: REQUIRED. Array of strings each referencing a Credential requested by the Verifier that can be used in session transcript. In [DIF.PresentationExchange], the string matches the id field in the Input Descriptor. In the Digital Credentials Query Language, the string matches the id field in the Credential Query. If there is more than one element in the array, the Wallet MUST use only one of the referenced Credentials for session transcript

credential_id and client_id has to be 1:1 mapping. so that RP can determine a client_id based on the credential_id

Copy link
Collaborator

@Sakurann Sakurann Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alternative proposal:
wallet puts used client_id in the response next to the credential:

{
  "my_credential": {
     “payload”: “eyJhbGci...QMA”,
     “client_id”: “asdf”
   }
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what prevents MITM replaying the request RP sent through the DC API:

  • for unsigned requests, origin is in the returned credential because origin == client_id
  • for signed request, expected_origins is in the signed request that MITM cannot modify

Copy link
Member

@bc-pi bc-pi Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what prevents MITM replaying the request RP sent through the DC API:

  • for unsigned requests, origin is in the returned credential because origin == client_id

  • for signed request, expected_origins is in the signed request that MITM cannot modify

Thank you for this summary and apologies for struggling with the concept during the most recent DCP call. One nit just for posterity is that for unsigned request the client_id contains the origin and is prefixed (it doesn't strictly equal origin).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about adding the client_id as an optional parameter (array of strings) to the Credential Query? That would simplify things quite a bit imho for the request:

  • If client_id is not present in the Credential Query: you use only one client_id in the request and nothing changes to the status quo (without multi-rp)
  • If client_id is present, the wallet can directly match which client ids are possible for each requested credential and choose accordingly

The DCQL vp_token gets an optional parameter client_id as well that is only included if more than one client_id was provided in the request (the DCQL query) and not present otherwise --> nothing changes for normal flows.

That way nothing changes for simple flows, but mult-rp flows extend the normal data structures without any unnecessary duplication unless I am missing something.

```

<{{examples/digital_credentials_api/signed_request_payload.json}}
This is an example of the payload of a signed OpenID4VP request used with the W3C Digital Credentials API in conjunction with JWS JSON Serialization:
tlodderstedt marked this conversation as resolved.
Show resolved Hide resolved

The signed request allows the Wallet to authenticate the Verifier using a trust framework other than the Web PKI utilized by the browser. An example of such a trust framework is the Verifier (RP) management infrastructure set up in the context of the eIDAS regulation in the European Union, in which case, the Wallet can no longer rely only on the web origin of the Verifier. This web origin MAY still be used to further strengthen the security of the flow. The external trust framework could, for example, map the Client Identifier to registered web origins.
<{{examples/digital_credentials_api/signed_request_payload.json}}

## Response

Expand Down Expand Up @@ -2677,6 +2728,14 @@ established by [@!RFC7515].
* Change Controller: OpenID Foundation Artifact Binding Working Group - [email protected]
* Specification Document(s): (#verifier_attestation_jwt) of this specification

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a DE on the JSON Web Signature and Encryption Header Parameters Registry so I can only speculate but if I were, I'd likely have questions...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like? ...

Copy link
Member

@bc-pi bc-pi Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the first question that would come to my mind is, "what the fuck is this?" but think about it from the perspective that this will maybe eventually be put forward through various bureaucratic entities to be considered as a registered JWS header. JOSE is a general purpose thing that is many layers removed from this document and the DE's might not know or care about OpenID4VP or any of this stuff. What is client_id and what does it do and why does it need or deserve to be general reserved JOSE header? This header contains a Client Identifier. and a pointer to RFC6749 are not, in my narrow view as the DE for a different registry, helpful at all.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a suggestion to enhance the description (below). I honestly don't know what to say more about it. I hope this works for you.

### client_id

* Header Parameter Name: `client_id`
* Header Parameter Description: This header contains a Client Identifier.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Header Parameter Description: This header contains a Client Identifier.
* Header Parameter Description: This header contains a Client Identifier. A Client Identifier is used in OAuth to identify a certain client. It is defined in [@!RFC6749], section 2.2.

* Header Parameter Usage Location: JWS
* Change Controller: IETF
* Specification Document(s): [@!RFC6749]

## Uniform Resource Identifier (URI) Schemes Registry

This specification registers the following URI scheme
Expand Down Expand Up @@ -2709,6 +2768,7 @@ The technology described in this specification was made available from contribut

-24

* Added support for multiple Client Identifiers and corresponding Request Signature to the DC API profile

-23

Expand Down
Loading