Skip to content

Conversation

@awoie
Copy link
Contributor

@awoie awoie commented Aug 27, 2024

This PR is still WIP.

This PR removes client_id_scheme by trying to crystalize the common features of existing client ID schemes (authentication, and validating redirect/response_uris) on top of existing client metadata retrieval mechanisms such as DCR, OpenID Federation or the new client_metadata parameter.

I figured that an activity diagram might help framing the discussion on Thursday's DCP WG call (thanks @javereec for this idea).

NOTE: a wallet does not have to support each method. I will make this more clear.

@javereec
Copy link
Contributor

Below is a diagram to potentially facilitate the discussion on how to verify these requests.

flowchart TD
    
    RS{Request Signed?} -->|Yes| URI{Client ID URI?}

    URI --> |Yes| X509
    URI --> |No| PRE

    X509{x5c,x5t header?} --> |Yes| X509A[X.509 Certificates]
    X509{x5c,x5t header?} --> |No| FED
    
    FED{Client ID URL?} --> |Yes| FEDA[OpenID Federation]
    FED{Client ID URL?} --> |No| DID
    
    DID{Client ID DID?} --> |Yes| DIDA[DID Resolution]
    DID{Client ID DID?} --> |No| PRE

    RS{Request Signed?} -->|No| PRE
    PRE{Client ID Pre-Registered?} --> |No| POL[Redirect URI = Client ID<br>Wallet Policy decision]
    PRE{Client ID Pre-Registered?} --> |Yes| PREA[Pre Registered <br>RFC6749]
Loading

@danielfett
Copy link
Contributor

For completeness, can you please expand the X.509 Certificates item?

@tlodderstedt
Copy link
Collaborator

@awoie can you please remove all occurrences of client_id_scheme? It feels like not all parts of the processing rules are adopted yet.

@danielfett
Copy link
Contributor

As discussed on the call, the PR in its current form does not address how to process a request (if more than one method is supported). Clearly defined processing rules that ensure that a request can never be modified by a third party such that the signature verification can be skipped or a signature can be replaced are the core of the problem in my opinion.

@awoie
Copy link
Contributor Author

awoie commented Aug 27, 2024

As discussed on the call, the PR in its current form does not address how to process a request (if more than one method is supported). Clearly defined processing rules that ensure that a request can never be modified by a third party such that the signature verification can be skipped or a signature can be replaced are the core of the problem in my opinion.

@danielfett Could you provide an example of a downgrade attack based on the existing language?

For signed requests, the request parameters are integrity protected:

  • Signed by X.509 certificates (included in request object) with SAN(s) that match the client_id and ensure linkage to the redirect_uri or response_uri.
  • Signed by DIDs that match the client_id, though there's no linkage to the redirect_uri or response_uri (which I believe is a potential issue).
  • Signed by cnf of Verifier attestations, attested by a trusted entity (such as an attestation issuer), which may include linkage to the redirect_uri or response_uri.
  • Signed by key obtained from OpenID Federation, where client metadata—including redirect_uris and jwks containing the verification key—is fetched from an authoritative source (via entity statements). The require_signed_request_object parameter could be set to enforce signing although probably not needed since OpenID Fed requires signing.
  • Pre-registered clients that provided their jwks and redirect_uri or response_uri during registration. Here, too, require_signed_request_object could be set to enforce signing.

For unsigned requests, the request parameters are either fetched from an authoritative source (pre-registered, perhaps with require_signed_request_object not enabled), or the client_id must match the redirect_uri or response_uri for simpler requests. In the latter case, a downgrade attack wouldn't make sense. To downgrade signed to unsigned, we could even require that for these in-band registrations (DID, X509, verifier attestation), client_id != redirect_uri.

Browser API is a different conversation.

A wallet would only enforce one of these methods if they were considered to be secure or even equally secure. The same applies to the verifier.

@nemqe
Copy link
Contributor

nemqe commented Aug 27, 2024

Just a note regarding DIDs and the comment about linkage to redirect_uri/response_uri.

Signed by DIDs that match the client_id, though there's no linkage to the redirect_uri or response_uri (which I believe is a potential issue).

For this I think it could be a mandate that linkage credentials need to be used (linked domains) so you have a direct link between the did-diddoc-domain.

@awoie
Copy link
Contributor Author

awoie commented Aug 29, 2024

Just a note regarding DIDs and the comment about linkage to redirect_uri/response_uri.

Signed by DIDs that match the client_id, though there's no linkage to the redirect_uri or response_uri (which I believe is a potential issue).

For this I think it could be a mandate that linkage credentials need to be used (linked domains) so you have a direct link between the did-diddoc-domain.

IMO, it is also questionable if this linkage is required for in-band request object authentication, i.e., where the client_id is authenticated by things included in the request object. Because if the request object is trusted to originate from the client_id, the redirect_uri/response_uri might NOT have to be linked to other things such as X.509 SAN(s), DID linked domain, or redirect_uris in the verifier attestation but this is separate discussion.

@awoie
Copy link
Contributor Author

awoie commented Aug 29, 2024

Perhaps a better visualization of the PR which shows that all of the request object authentication methods don't have to be applied in a particular order. The diagram below does not include redirect/response_uri validation yet but the bullet points above show how this can be done. Perhaps in-band registration is the better term for x.509/DID/verifier attestation where the request object is authenticated against the client ID using parameters that are provided in band and additional client metadata is typically provided using the client_metadata parameter.

flowchart TD
    start --> pre
    start --> fed
    start --> inband
    
    pre[Pre-registered] -->|client_id is pre-registered| prev
    fed[OpenID Federation] -->|client_id is OpenID Federation Entity ID,<br>i.e., URI with OpenID Fed well-known| fedv[Verify signature using<br>resolved OpenID Fed metadata] --> con[Continue]
        
    inband[Inband registration] -->IS{is request signed?}-->|No| usv
    IS -->|Yes|II{client_id matches<br>redirect/response_uri?} -->|Yes| rej[Reject]
    II -->|No| inbandss[Determine verification key]
    inbandss -->|x5c, x5t in JAR| x509v[Verify signature using<br>corresponding certificate] --> con
    inbandss -->|jwt/verifier attestation in JAR| vav[Verify signature using<br>cnf claim] --> con
    inbandss -->|client_id is a DID| didv[Verify signature<br>using key from DID Document] --> con

    prev[Fetch client metadata] --> B{Is request<br>signed?} -->|Yes| C[Verify signature using<br>jwks from client metadata] --> con
    B -->|No| D{Is require<br>request object<br>signing set?} -->|Yes| con
    D -->|No| rej

    usv{client_id matches<br>redirect/response_uri?} -->|Yes| con
Loading

@javereec
Copy link
Contributor

@awoie regarding the diagram.

When the request is not signed and client_id = redirect_uri/response_uri I think we must continue, not reject.

When a request comes in, I think we can be more clear about what we need to evaluate first. Is this the client_id or wether the request is signed or not. The entry point is not quite clear.

@awoie
Copy link
Contributor Author

awoie commented Aug 29, 2024

@awoie regarding the diagram.

When the request is not signed and client_id = redirect_uri/response_uri I think we must continue, not reject.

Indeed, that was just a bug in the diagram. I fixed it.

@awoie
Copy link
Contributor Author

awoie commented Aug 29, 2024

@awoie regarding the diagram.

When a request comes in, I think we can be more clear about what we need to evaluate first. Is this the client_id or wether the request is signed or not. The entry point is not quite clear.

IMO, this is a wallet policy since it is also a wallet policy which methods to support at all. It should make no difference if we prescribed a specific order or not unless I'm missing something.

Copy link
Member

@selfissued selfissued left a comment

Choose a reason for hiding this comment

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

Approved with editorial suggestions.


The following is a non-normative example of a request when `client_id` equals `redirect_uri`.
The following is a list of methods defined by this specification that MAY be used by the Wallet to authenticate the Request Object and to verify that the `redirect_uri` or `response_uri` belongs to the Client:
- Pre-registered: If the Client is pre-registered, the `jwks` Client Metadata parameter provided upon registration MUST be used to verify the signature of the Request Object. The `redirect_uris` Client Metadata parameter is used to verify the `redirect_uri` or `response_uri` for that Client. Note that the Wallet determines whether the Client is pre-registered.
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that the Wallet determines whether the Client is pre-registered.

out of curiosity, do we need this note, isn't it implied?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is implied but I remember we had a discussion about this topic, so I kept that language for clarity.

Copy link
Contributor

Choose a reason for hiding this comment

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

If enabled together, how does the wallet distinguish between a pre-registered client https://example.com from one authenticating with an x509 cert for that URL?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can add that wallets and wallet providers MUST implement the OAuth Security BCP that suggests to use random client IDs where there is no clash possible.

awoie and others added 6 commits September 2, 2024 21:38
Co-authored-by: Michael B. Jones <michael_b_jones@hotmail.com>
Co-authored-by: Nemanja Patrnogic <3052405+nemqe@users.noreply.github.com>
Co-authored-by: Michael B. Jones <michael_b_jones@hotmail.com>
Co-authored-by: Michael B. Jones <michael_b_jones@hotmail.com>
Co-authored-by: Michael B. Jones <michael_b_jones@hotmail.com>
Co-authored-by: Michael B. Jones <michael_b_jones@hotmail.com>
If the Authorization Request is signed, the Wallet MUST authenticate the Request Object against the `client_id` contained in the Request Object. In this case, any `jwks` parameter in the `client_metadata` parameter MUST NOT be used to verify the signature of the Request Object.

* `redirect_uri`: This value indicates that the Verifier's Redirect URI (or Response URI when Response Mode `direct_post` is used) is also the value of the Client Identifier. The Authorization Request MUST NOT be signed. The Verifier MAY omit the `redirect_uri` Authorization Request parameter (or `response_uri` when Response Mode `direct_post` is used). All Verifier metadata parameters MUST be passed using the `client_metadata` parameter defined in (#vp_token_request).
If the Verifier Metadata is not obtained from a trusted source and if the Authorization Request is unsigned, the Wallet MUST verify that the `client_id` matches the `redirect_uri` or `response_uri` parameter. Examples for trusted sources include prior registration (e.g., using [@!RFC7591]) or other out-of-band processes that allow the Wallet to retrieve trusted Verifier Metadata for a particular Client.
Copy link
Contributor

Choose a reason for hiding this comment

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

It should be stated that this requirement only applies if the client_id is present.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not convinced this matters, isn't client_id mandatory in all cases where redirect_uri or response_uri can be used? (i.e. I think you can only omit client_id in unsigned browser API requests, where redirect_uri and response_uri aren't permitted to be used).

If the Verifier Metadata is not obtained from a trusted source and if the Authorization Request is unsigned, the Wallet MUST verify that the `client_id` matches the `redirect_uri` or `response_uri` parameter. Examples for trusted sources include prior registration (e.g., using [@!RFC7591]) or other out-of-band processes that allow the Wallet to retrieve trusted Verifier Metadata for a particular Client.

The following is a non-normative example of a request when `client_id` equals `redirect_uri`.
The following is a list of methods defined by this specification that MAY be used by the Wallet to authenticate the Request Object and to verify that the `redirect_uri` or `response_uri` belongs to the Client:
Copy link
Contributor

Choose a reason for hiding this comment

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

It states that the following mechanisms MAY be used, but the mechanisms themselves contain MUST. What does this mean exactly, some options:

  1. It's optional to use these mechanisms even when the conditions are applicable, but if the mechanism is used by the wallet, the requirements have to be followed.
  2. When the conditions are applicable the mechanism MUST be used, otherwise an error must be given.
  3. When the conditions are applicable the mechanism MUST be used, otherwise the client is considered not authenticated, with the consequences being out of scope.

Something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The PR aims to allow for Option 1. I agree that the combination of MAY and MUST is not clear.

Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if the request has contradicting properties, e.g., fulfills the rules in X.509 and Federation at the same time?

The following is a non-normative example of a request when `client_id` equals `redirect_uri`.
The following is a list of methods defined by this specification that MAY be used by the Wallet to authenticate the Request Object and to verify that the `redirect_uri` or `response_uri` belongs to the Client:
- Pre-registered: If the Client is pre-registered, the `jwks` Client Metadata parameter provided upon registration MUST be used to verify the signature of the Request Object. The `redirect_uris` Client Metadata parameter is used to verify the `redirect_uri` or `response_uri` for that Client. Note that the Wallet determines whether the Client is pre-registered.
- X.509 certificates: If the Request Object contains an `x5c`, `x5t`, or `x5t#S256` header parameter, after validating the X.509 certificate chain, the Wallet MUST use the public key from the leaf-certificate of the X.509 certificate chain to verify the signature of the Request Object. In this case, the leaf-certificate MUST include a`dNSName` Subject Alternative Name (SAN) [RFC5280] or `uniformResourceIdentifier` SAN [RFC5280] that matches the `client_id`. If the Wallet can establish trust in the `client_id` authenticated through the certificate, e.g. because the `client_id` is contained in a list of trusted Client Identifiers, it MAY allow the Client to freely choose the `redirect_uri` or `response_uri` value. If not, the `redirect_uri` or `response_uri` value MUST match the `client_id` or FQDN of the `client_id`.
Copy link
Contributor

Choose a reason for hiding this comment

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

X.509 certificates should not be required to contain a SAN. It's possible to authenticate a client, without that authentication being bound to a SAN. (as an example, this is also what is used for in-person relying party authentication)

In case of the browser api, the requirement that the client_id must match the response_uri is not applicable and this should be stated as such.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree with this. It is questionable what the value add of SAN is in this context if the root is trusted.

Copy link
Contributor Author

@awoie awoie Sep 5, 2024

Choose a reason for hiding this comment

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

I believe client_id must match response_uri should not be a requirement. It might be useful though that redirect_uri/response_uri (or via FQDN) is included in the SAN in some way but it shouldn't be required. Since Browser API doesn't have redirect_uri/response_uri, this wouldn't apply to browser API.

- X.509 certificates: If the Request Object contains an `x5c`, `x5t`, or `x5t#S256` header parameter, after validating the X.509 certificate chain, the Wallet MUST use the public key from the leaf-certificate of the X.509 certificate chain to verify the signature of the Request Object. In this case, the leaf-certificate MUST include a`dNSName` Subject Alternative Name (SAN) [RFC5280] or `uniformResourceIdentifier` SAN [RFC5280] that matches the `client_id`. If the Wallet can establish trust in the `client_id` authenticated through the certificate, e.g. because the `client_id` is contained in a list of trusted Client Identifiers, it MAY allow the Client to freely choose the `redirect_uri` or `response_uri` value. If not, the `redirect_uri` or `response_uri` value MUST match the `client_id` or FQDN of the `client_id`.
- DID Resolution: If the `client_id` in the Request Object is a DID, the signature of the Request Object MUST be verified using a public key obtained from a `verificationMethod` property of a DID Document. Since a DID Document can include multiple public keys, the particular public key used to sign the request MUST be identified by the `kid` header parameter. To obtain the DID Document, the Wallet MUST use DID Resolution as defined by the DID method used by the Verifier. (Note that it is currently unspecified how to verify the `redirect_uri` or `response_uri` for DIDs.)
- Verifier Attestation: If the Request Object contains a Verifier Attestation JWT, as defined in (#verifier_attestation_jwt), the Wallet MUST verify the signature of the Request Object using the public key in the `cnf` claim in the Verifier Attestation JWT. This serves as proof of possession of this key. Additionally, the `client_id` MUST equal the `sub` claim value in the Verifier Attestation JWT. The Wallet MUST validate the signature on the Verifier Attestation JWT. The `iss` claim value of the Verifier Attestation JWT MUST identify a party the Wallet trusts for issuing Verifier Attestation JWTs. If the issuer of the Verifier Attestation JWT includes a `redirect_uris` claim in the Verifier Attestation, the Wallet MUST verify that the `redirect_uri` or `response_uri` request parameter value exactly matches one of the `redirect_uris` array values.
- OpenID Federation: If the `client_id` in the Request Object is an Entity Identifier, as defined in OpenID Federation [@!OpenID.Federation], the processing rules specified in OpenID Federation MUST be followed. When this is the case, the Entity Configuration for the Client is obtained at the path `<client_id>/.well-known/openid-federation`. Automatic Registration, as defined in OpenID Federation, MUST be used. The Authorization Request MAY also contain a `trust_chain` parameter, which can optimize the process of obtaining metadata. The `jwks` parameter of the resolved Verifier metadata obtained from the Trust Chain after applying the policies, according to OpenID Federation, MUST be used to verify the signature of the Request Object. The Wallet MUST verify that the `redirect_uri` or `response_uri` request parameter matches one of the entries of the `redirect_uris` parameter of the resolved metadata.
Copy link
Contributor

Choose a reason for hiding this comment

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

How does the Wallet identify if the client_id is an Entity Identifier?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the wallet supports OpenID Federation, the wallet would check if the client_id is a HTTPS URI and try to fetch OpenID Federation well-known.

It is a policy decision by the Wallet which method to choose to authenticate the Request Object and whether to accept unsigned Authorization Requests.

The following is a non-normative example of a header and a body of a signed Request Object when Client Identifier scheme is a `did`:
Note: To prevent downgrade attacks, the Client can choose to enable only specific methods in the Request Object, such as the ones defined above.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is completely insufficient. Why do we allow using more than one method if it is seemingly insecure to do so?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps the language can be improved but a Client would not support options and set parameters in the request if they were not equally secure.

To use `client_id_scheme` values `entity_id`, `did`, `verifier_attestation`, `x509_san_dns`, and `x509_san_uri`, Verifiers MUST be confidential clients. This might require changes to the technical design of native apps as such apps are typically public clients.

Other specifications can define further values for the `client_id_scheme` parameter. It is RECOMMENDED to use collision-resistant names for such values.
Other specifications or ecosystem regulations MAY define rules complementing the rules defined above, but such extensions are out of scope of this specification.
Copy link
Contributor

Choose a reason for hiding this comment

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

What are the constraints for those new rules in order to safely work with the rules defined above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I would assume they should do 1 or 2 things like the other in-band client registration methods do:

  1. authenticate the request that it was originated by the client_id; this is typically done by verifying the signature on the signed request; for browser API, this might be based on origin.
  2. optionally check if the redirect_uri/response_uri is linked to the client_id; but this requirement is kind of not consistently achieved in the current version of the spec either, so I would assume it is optional;

_vp%22:%7B%22proof_type%22:%5B%22Ed25519Signature201
8%22%5D%7D%7D%7D
```
If the Verifier Metadata is not obtained from a trusted source and if the Authorization Request is unsigned, the Wallet MUST verify that the `client_id` matches the `redirect_uri` or `response_uri` parameter. Examples for trusted sources include prior registration (e.g., using [@!RFC7591]) or other out-of-band processes that allow the Wallet to retrieve trusted Verifier Metadata for a particular Client.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this method always enabled?

Copy link
Contributor Author

@awoie awoie Sep 3, 2024

Choose a reason for hiding this comment

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

No, it is not. We need to adapt the language, also @martijnharing had a similar comment here #237 (comment)

The following is a list of methods defined by this specification that MAY be used by the Wallet to authenticate the Request Object and to verify that the `redirect_uri` or `response_uri` belongs to the Client:
- Pre-registered: If the Client is pre-registered, the `jwks` Client Metadata parameter provided upon registration MUST be used to verify the signature of the Request Object. The `redirect_uris` Client Metadata parameter is used to verify the `redirect_uri` or `response_uri` for that Client. Note that the Wallet determines whether the Client is pre-registered.
- X.509 certificates: If the Request Object contains an `x5c`, `x5t`, or `x5t#S256` header parameter, after validating the X.509 certificate chain, the Wallet MUST use the public key from the leaf-certificate of the X.509 certificate chain to verify the signature of the Request Object. In this case, the leaf-certificate MUST include a`dNSName` Subject Alternative Name (SAN) [RFC5280] or `uniformResourceIdentifier` SAN [RFC5280] that matches the `client_id`. If the Wallet can establish trust in the `client_id` authenticated through the certificate, e.g. because the `client_id` is contained in a list of trusted Client Identifiers, it MAY allow the Client to freely choose the `redirect_uri` or `response_uri` value. If not, the `redirect_uri` or `response_uri` value MUST match the `client_id` or FQDN of the `client_id`.
- DID Resolution: If the `client_id` in the Request Object is a DID, the signature of the Request Object MUST be verified using a public key obtained from a `verificationMethod` property of a DID Document. Since a DID Document can include multiple public keys, the particular public key used to sign the request MUST be identified by the `kid` header parameter. To obtain the DID Document, the Wallet MUST use DID Resolution as defined by the DID method used by the Verifier. (Note that it is currently unspecified how to verify the `redirect_uri` or `response_uri` for DIDs.)
Copy link
Contributor

Choose a reason for hiding this comment

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

As above, how is a pre-registered client did:bla:blub distinguished from one using did:bla:blub as a did?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A pre-registered client would not include a DID for the kid value.

Independently, if a wallet supports both DID and pre-registered clients, the wallet would check their preferred way to authenticate the request first. This might be DID-based or based on pre-registered client metadata.

@danielfett
Copy link
Contributor

To reiterate what I said on the call, the current PR does not ensure that

  • the verifier's expectation on what was actually checked when it receives a presentation with its client id in the "aud" claim matches what the wallet checked, and
  • two implementations of this draft that, for example, allow x509 and pre-registered clients, behave the same way and do the same checks.

This is an extremely critical part of the spec and therefore we need to ensure to get it right.

Co-authored-by: Nemanja Patrnogic <3052405+nemqe@users.noreply.github.com>
@awoie
Copy link
Contributor Author

awoie commented Sep 5, 2024

To reiterate what I said on the call, the current PR does not ensure that

  • the verifier's expectation on what was actually checked when it receives a presentation with its client id in the "aud" claim matches what the wallet checked, and

This can only be guaranteed if the public verification key is included in the VP, e.g., aud=<jwk-thumbprint>:<client_id>. This would also mitigate the concern that even within an existing client ID scheme, e.g., x509, verifier attestation etc., and if the client ID scheme was included in the response, the verifier does not know which credential (certificate, or verifier attestation etc.) was used to authenticate the client ID if a verifier supports multiple in-band client credentials of the same type but adhering to different security levels or ecosystem requirements. Note that it is possible that a verifier obtains multiple credentials for the same client ID.

  • two implementations of this draft that, for example, allow x509 and pre-registered clients, behave the same way and do the same checks.

This is a performance concern, not a security concern, if we consider my comment above. We can suggest an order in the PR to guide wallets.

@awoie
Copy link
Contributor Author

awoie commented Sep 5, 2024

This is a performance concern, not a security concern, if we consider my comment above. We can suggest an order in the PR to guide wallets.

For example, we could suggest the following order if performance is a concern.

If the request is signed:

  • Public keys in the client_metadata parameter MUST NOT be used to verify the signature of the signed request.

  • Pre-registered Clients:

    • Wallets or Wallet Providers must implement the security OAuth Best Current Practice (BCP) that ensures random client IDs for pre-registered clients.
    • If the wallet supports pre-registered clients, and the client ID is pre-registered, retrieve the public key from the client metadata to verify the signature of the request.
  • x509 Certificate:

    • If an x5c, x5t, or x5t#S256 JWT header is present, validate the X.509 certificate chain and resolve the public key from the corresponding leaf certificate to verify the signed request.
  • Verifier Attestations:

    • If the wallet supports verifier attestations and if the signed request contains a verifier attestation in the JWT header indicated by the typ JWT header , verify the verifier attestation is trusted and resolve the public key from the cnf claim of the verifier attestation to verify the signed request.
  • DID Document:

    • If the wallet supports Decentralized Identifiers (DIDs), and the client ID is a DID indicated by the client ID starting with the did: URI scheme, attempt to resolve the public key using the DID resolution process to verify the signature of the signed request.
  • OpenID Federation:

    • If the wallet supports OpenID Federation, and the client ID is a HTTPS URI, retrieve the public key from the resolved OpenID Federation metadata to verify the signature of the signed request.
  • Ecosystem-specific Support:

    • Other mechanisms that are out of scope of this specification MAY be used to obtain a public key to verify the signature of the request object, if the wallet can verify that public key is authoritative for the provided client ID protected by the signed request.
  • Verification Failure:

    • If the signature of the signed request cannot be verified, the request MUST be rejected.

If the request is not signed:

  • Pre-registered Clients:

    • If the wallet supports pre-registered clients, and the client ID is pre-registered, ensure that require_request_object_signing is set to false or omitted from the client metadata. The request MUST be rejected if require_request_object_signing is true.
  • Client ID is Redirect URI:

    • If the request was not received via the Digital Credentials API as defined in Appendix A, verify the client_id equals redirect_uri or response_uri. Otherwise, the request MUST be rejected.

If the request was received via the browser API:

  • Check that origin received via the platform matches one of the expected_origins. Otherwise, the request MUST be rejected. (this probably does not have to go into the section since it is covered in Appendix A).

Body
This specification defines the following mechanisms for In-band Registration for signed requests:
* X.509 Certificates: If supported by the Wallet, the request is signed, and any of the `x5c`, `x5t`, or `x5t#S256` JWT headers are present, the Wallet MUST validate the corresponding X.509 certificate chain and use the public key from the leaf certificate to verify the signature of the signed request to authenticate the request. Additionally, the Wallet MUST check that the `client_id` in the signed request matches any X.509 Subject Alternative Name (SAN) value of the leaf certificate. If the Wallet can establish trust in the `client_id` authenticated through the leaf certificate, e.g., because the `client_id` is contained in a list of trusted Client Identifiers, it MAY allow the Client to freely choose the `redirect_uri` or `response_uri` value. If not, the `redirect_uri` or `response_uri` value MUST match the `client_id` or FQDN of the `client_id`. If either verification fails, the Wallet MUST reject the request, otherwise processing continues.
* Verifier Attestations: If supported by the Walletm the request is signed, and the signed request contains a `jwt` JWT header that is a Verifier Attestation JWT, the Wallet MUST use the public key in the `cnf` claim in the Verifier Attestation JWT to verify the signatuer of the signed request. This serves as proof of possession of this key. Additionally, the `client_id` MUST equal the `sub` claim value in the Verifier Attestation JWT. The Wallet MUST validate the signature on the Verifier Attestation JWT. The `iss` claim value of the Verifier Attestation JWT MUST identify a party the Wallet trusts for issuing Verifier Attestation JWTs. If the issuer of the Verifier Attestation JWT includes a `redirect_uris` claim in the Verifier Attestation, the Wallet MUST verify that the `redirect_uri` or `response_uri` request parameter value exactly matches one of the `redirect_uris` array values. If either of the checks fail, the Wallet MUST reject the request, otherwise processing continues.
Copy link
Contributor

@nemqe nemqe Sep 11, 2024

Choose a reason for hiding this comment

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

small typo

Suggested change
* Verifier Attestations: If supported by the Walletm the request is signed, and the signed request contains a `jwt` JWT header that is a Verifier Attestation JWT, the Wallet MUST use the public key in the `cnf` claim in the Verifier Attestation JWT to verify the signatuer of the signed request. This serves as proof of possession of this key. Additionally, the `client_id` MUST equal the `sub` claim value in the Verifier Attestation JWT. The Wallet MUST validate the signature on the Verifier Attestation JWT. The `iss` claim value of the Verifier Attestation JWT MUST identify a party the Wallet trusts for issuing Verifier Attestation JWTs. If the issuer of the Verifier Attestation JWT includes a `redirect_uris` claim in the Verifier Attestation, the Wallet MUST verify that the `redirect_uri` or `response_uri` request parameter value exactly matches one of the `redirect_uris` array values. If either of the checks fail, the Wallet MUST reject the request, otherwise processing continues.
* Verifier Attestations: If supported by the Wallet, the request is signed, and the signed request contains a `jwt` JWT header that is a Verifier Attestation JWT, the Wallet MUST use the public key in the `cnf` claim in the Verifier Attestation JWT to verify the signatuer of the signed request. This serves as proof of possession of this key. Additionally, the `client_id` MUST equal the `sub` claim value in the Verifier Attestation JWT. The Wallet MUST validate the signature on the Verifier Attestation JWT. The `iss` claim value of the Verifier Attestation JWT MUST identify a party the Wallet trusts for issuing Verifier Attestation JWTs. If the issuer of the Verifier Attestation JWT includes a `redirect_uris` claim in the Verifier Attestation, the Wallet MUST verify that the `redirect_uri` or `response_uri` request parameter value exactly matches one of the `redirect_uris` array values. If either of the checks fail, the Wallet MUST reject the request, otherwise processing continues.

Comment on lines +464 to +466
To prevent downgrade attacks, the Wallet MUST cyrptographically bind the JWK Thumbprint of the public key that was used to verify the signature of the signed request, to the Verifiable Presentation(s) in the response. The exact mechanism of how the JWK Thumbprint is bound to the Verifiable Presentation(s) is defined per Credential Format. For example, for SD-JWT VC, the JWK Thumbprint is prepended to the `client_id` value and included in the `aud` claim of the the Key Binding JWT, e.g., `aud=<JWK-Thumbprint>:<client_id>`.

Other specifications can define further values for the `client_id_scheme` parameter. It is RECOMMENDED to use collision-resistant names for such values.
If the Verifier provided a signed request to the Wallet, the Verifier MUST verify the JWK Thumbprint included in the Verifiable Presentation(s) of the response corresponds to the key that signed the original request. The response MUST be rejected if verification fails, otherwise processing continues.
Copy link
Contributor

Choose a reason for hiding this comment

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

This section confuses me a bit, but I am easily confused. Seems a bit like "can you repeat to me what I said so I am sure you understood it".

Am a getting it right? I might be missing a smallish example of possible vectors and surfaces that we are trying to mitigate i.e. the reasoning behind this "proof of computation".

@jogu
Copy link
Collaborator

jogu commented Sep 27, 2024

I think we've achieved consensus around #266 so I think this PR is no longer needed and hence closing it to clean up the PR list - many thanks go to Oliver/Tobias/etc for help moving the conversation along!

@jogu jogu closed this Sep 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants