Skip to content

Conversation

@c2bo
Copy link
Member

@c2bo c2bo commented Jun 5, 2025

Closes #507

This is the option creating a JWT for credential request with either the dpop or wallet attestation keys.

* in the JOSE header,
* `alg`: REQUIRED. A digital signature algorithm identifier such as per IANA "JSON Web Signature and Encryption Algorithms" registry [@IANA.JOSE]. It MUST NOT be `none` or an identifier for a symmetric algorithm (MAC).
* `typ`: REQUIRED. MUST be `credential-request+jwt`, which explicitly types the Credential Request JWT as recommended in Section 3.11 of [@!RFC8725].
* `kid`: OPTIONAL. MUST be `dpop`, or `wallet-attestation`. Identifies the key the Wallet used to sign the Credential Request. If the `kid` is `dpop`, the Credential Request JWT is signed with the DPoP key of the refresh or access token. If the `kid` is `wallet-attestation`, the key that is used to sign the proof of possession for the Wallet Attestation as described in (#walletattestation) is used to sign the Credential Request JWT. If not present, the key used to sign the Credential Request JWT defaults to the DPoP key.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any particular reason to specify the value vs just say it must be the kid of the key used for dpop or wallet-attestation? (seems slightly odd to force the value, the client and the verifier should be aware of that key and its kid, right?).

Copy link
Member Author

@c2bo c2bo Jun 12, 2025

Choose a reason for hiding this comment

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

Right now kid is not required for key attestation and does not exist for dpop since we only have the cnf claim to convey the key. My idea with these static identifiers was to allow an easy way to convey which key was used, but I agree it doesn't feel very clean to me. Any better ideas?

Copy link

Choose a reason for hiding this comment

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

What is the reason to be using the kid to make the distinction?
A kid value is already present on a JWK in a lot of cases. kid's then are being used for instance when DIDs are involved, pointing to an actual identifier of the key (VM relationship). This means that now any Key Management System needs to do identifier juggling.

Is there a specific reason why another header cannot be used?

Copy link
Member Author

Choose a reason for hiding this comment

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

We could use something else. We could also decide to tie this mechanism to DPoP since the RS should know the DPoP key anyway and remove any identifier - that might be the cleanest way if people are fine with limiting this to the combination with DPoP

* in the JOSE header,
* `alg`: REQUIRED. A digital signature algorithm identifier such as per IANA "JSON Web Signature and Encryption Algorithms" registry [@IANA.JOSE]. It MUST NOT be `none` or an identifier for a symmetric algorithm (MAC).
* `typ`: REQUIRED. MUST be `credential-request+jwt`, which explicitly types the Credential Request JWT as recommended in Section 3.11 of [@!RFC8725].
* `kid`: OPTIONAL. MUST be `dpop`, or `wallet-attestation`. Identifies the key the Wallet used to sign the Credential Request. If the `kid` is `dpop`, the Credential Request JWT is signed with the DPoP key of the refresh or access token. If the `kid` is `wallet-attestation`, the key that is used to sign the proof of possession for the Wallet Attestation as described in (#walletattestation) is used to sign the Credential Request JWT. If not present, the key used to sign the Credential Request JWT defaults to the DPoP key.
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason not to just make the kid mandatory?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, it should probably be REQUIRED


* in the JWT body,
* `iat`: REQUIRED (number). Integer for the time at which the key attestation was issued using the syntax defined in [@!RFC7519].
* `credential_request`: An Object containing the Credential Request parameters:
Copy link
Contributor

Choose a reason for hiding this comment

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

it'd be nice if we just defined this once and used it everywhere.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wasn't sure if just linking to 8.2 as the content of this object would be sufficient Happy to change that - it would also make everything a lot easier to manage & read.

@GarethCOliver
Copy link
Contributor

seems reasonable to me

@c2bo
Copy link
Member Author

c2bo commented Jun 12, 2025

Updated to only allow DPoP key and remove kid + reference the parameter section instead of re-defining. This makes the PR a lot smaller and cleaner imho

@Sakurann
Copy link
Collaborator

WG discussion:
direction after the discussion:

  • direction seems to be that integrity protection of the credential response encryption key cannot be achieved in a meaningful way as long as trust relationship between issuer and the wallet frontend is established through the wallet backend. at least without relying on OS specific mechanisms.
  • to protect the credential response encryption key from non-backend attackers, credential request encryption is sufficient, if credential request encryption is mandatory with credential response encryption?

rest of the discussion:

  • why mobile OS provided key can't authenticate the frontend to the issuer? it's not the key attestation that proves frontend's integrity
  • what requirements we have regarding the key that response is encrypted to?
    • that key needs to be tied to the wallet that controls the access token. can't be an arbitrary key. all key/wallet attestations sent in the credential request are generated by the wallet backend.
  • we are facilitating architecture that involves wallet backend - how do existing implementations cope with the wallet backend being in the middle?
    • these implementations use android OS key attestation directly. works because wallet backend is a different entity from the android OS PKI?
  • what authenticates the app is wallet attestation, not key attestation
  • Lee had a suggestion to sign over the encryption key in the credential response. but that, malicious backend can spoof.

@tplooker
Copy link
Contributor

tplooker commented Jun 17, 2025

Thanks for the notes @Sakurann, few comments inline.

direction seems to be that integrity protection of the credential response encryption key cannot be achieved in a meaningful way as long as trust relationship between issuer and the wallet frontend is established through the wallet backend. at least without relying on OS specific mechanisms.

If we supported signed credential requests, where the signing key was the DPoP key I think this would allow for an architecture that doesn't require a wallet backend, if that is what this is intended to mean? Which is what this PR does?

I do however think supporting models that allow for using OS specific mechanisms like key attestations is important too.

to protect the credential response encryption key from non-backend attackers, credential request encryption is sufficient, if credential request encryption is mandatory with credential response encryption?

Not sure I follow this, encryption approaches that involve a static key pair (the credential issuers) and an ephemeral key pair (the wallets) are not really immune from MITM attacks where an attacker can just generate a new ephemeral encryption key and encrypt a new request to the credential issuer. The issue essentially is, how to establish trust in who encrypted the request.

@jogu
Copy link
Contributor

jogu commented Jun 17, 2025

Thanks for the notes @Sakurann, few comments inline.

direction seems to be that integrity protection of the credential response encryption key cannot be achieved in a meaningful way as long as trust relationship between issuer and the wallet frontend is established through the wallet backend. at least without relying on OS specific mechanisms.

If we supported signed credential requests, where the signing key was the DPoP key I think this would allow for an architecture that doesn't require a wallet backend, if that is what this is intended to mean? Which is what this PR does?

The goal of this work was, as I understand it, to prevent a malicious wallet backend from being able to access credentials when encrypted credential requests & responses are being passed from the wallet app to the wallet backend and then to the issuer. The discussion in the WG reached the conclusion that there is no realistic way to provide this guarantee. It is pretty much inherent in the current model that the wallet backend (which is pretty much required for any architecture that uses OAuth 2.0 Attestation-Based Client Authentication) has to be trusted.

The discussion further evolved onto stating that the purpose of request/response encryption was to avoid the wallet backend unnecessarily seeing PII.

I do however think supporting models that allow for using OS specific mechanisms like key attestations is important too.

Yes, but these don't help solve the problem (an attestation that a key is in a hardware backed store doesn't tell you whether it's on the intended device or a device the attacker is using).

to protect the credential response encryption key from non-backend attackers, credential request encryption is sufficient, if credential request encryption is mandatory with credential response encryption?

Not sure I follow this, encryption approaches that involve a static key pair (the credential issuers) and an ephemeral key pair (the wallets) are not really immune from MITM attacks where an attacker can just generate a new ephemeral encryption key and encrypt a new request to the credential issuer. The issue essentially is, how to establish trust in who encrypted the request.

I think that is exactly the issue - we couldn't find a way to establish that trust.

@jogu
Copy link
Contributor

jogu commented Jun 17, 2025

As per Kristina's comment above, and further discussion on today's WG call - closing for now. We can revisit in the future. (And thanks to Christian for putting together these PRs so we had some clear options to discuss the pros & cons of - I think that really helped us reach a conclusion).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integrity of the JWK used for Credential Response encryption

7 participants