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

Mechanism for trust frameworks to limit the credentials & claims that a verifier is allowed to request #232

Open
jogu opened this issue Aug 25, 2024 · 29 comments

Comments

@jogu
Copy link
Collaborator

jogu commented Aug 25, 2024

#182 and #189 both propose solutions to an underlying problem - that ecosystems / trust frameworks want to have some way to restrict the credentials and claims within those credentials that a verifier can request.

Unfortunately the mechanisms mentioned in both issues are incompatible with the browser API, as they would require the wallet to fetch an external network resource in order to know if it has any credentials that match the request, and (on Android) the wallet must be able to tell the OS/browser what credentials it has that match the request in a sandboxed request matcher without doing any network operations to avoid leaking information about the request to all installed wallets without user consent (or possibly #189 requires comparison of the presentation exchange JSON, which is akin to canonicalisation of JSON and a known interoperability issue).

This issue hence avoids suggesting a full solution, but I observe that for compatibility with the browser API it seems like the solution must take one of two forms:

  1. The full information as to what the verifier is allowed to request is included inline in the request, in a way that the wallet can later verify if it is genuine (e.g. a JWT signed by a third party that contains the query), or:
  2. Some kind of permission language is defined that allows a wallet (once a credential has been selected) to check if a request is permitted for this verifier or not.

I think initially we should focus on whether there are any ways other than '1' or '2' to achieve this, and try to figure out which of those two solutions is preferred.

@alenhorvat
Copy link

alenhorvat commented Aug 26, 2024

Hi. @jogu I will continue with the discussion here.

Thanks @alenhorvat ! I think what you are suggesting is a variant of my second proposal (essentially a 'permissions' language of some kind) on #232 except it's basically using some of the properties of presentation exchange as the permissions language, which I think is slightly different from the original proposal above but I'm not 100% clear on the original proposal yet?

Actually, you need both properties 1 and 2. In 1, if my understanding is correct, you define how information is passed from the verifier to the wallet. For this, we tested the 3 options I mentioned

  • embedded via authentication request (client metadata)
  • referenced in the authentication request (client metadata)
  • wallet initiates a new VP flow (more advanced, can be discarded)

Your point 2, in my understanding, defines that we need a permission language to learn whether the wallet allows to share the VC (if the RP met the requirements); For this, we put the policy in the VC itself (it's a design option we took, works for the cases we have, it has limitations);

@peppelinux , if I understood you well, you proposed that this point is reversed: instead of defining the policies in a VC, policies are defined externally and hosted by the RP. I believe the VC should in any case (regardless of the format, ...) contain information whether or not it is expected from the RP to prove they have the right to request the VC.

I don't think "information is fetched from the .well-known (as described here)" works with the browser API as the information in the well-known is necessary to know whether the wallet has any credentials that match the request, but you can't fetch the well-known until the user has selected a credential?

Correct, hence, we included an option where the information is embedded in the authentication request. We put it in the client metadata. We also need this for cases when wallet might have limited access to the web.
I don't know the details of the browser API that's planned, but I'm more than happy to look into it.

@jogu
Copy link
Collaborator Author

jogu commented Aug 26, 2024

Thanks @alenhorvat

You can read about the browser API here: https://openid.github.io/OpenID4VP/openid-4-verifiable-presentations-wg-draft.html#name-openid4vp-profile-for-the-w - it's pretty important as it solves issues like cross-device flow security and helping the user experience (rather than having to pick a wallet, the user picks a credential they want to share). However that also imposes limitations (like the one I mentioned of the wallet not being able to access the intranet whilst checking if it has a a credential that matches a request or not).

@alenhorvat
Copy link

rather than having to pick a wallet, the user picks a credential they want to share

The model I mentioned could address this requirement. (additional information is embedded in the request)

like the one I mentioned of the wallet not being able to access the intranet whilst checking if it has a a credential that matches a request or not

Specification currently states: The signed request allows the Wallet to authenticate the Verifier using a trust framework other than the Web PKI utilized by the browser.

IMO, in this case, the wallet should be able to execute additional logic. Or?

@jogu
Copy link
Collaborator Author

jogu commented Aug 26, 2024

IMO, in this case, the wallet should be able to execute additional logic. Or?

The wallet can execute additional logic but only after the user has selected the credential they want to share and the wallet takes control of the UX. So like you say everything needed for figuring out if a credential matches the request or not needs to be embedded in the request. (So in the case of a signed request it is possible that the user can select a credential, then the wallet is launched and is able to verify the signature on the request and it turns out to be invalid, meaning the wallet has to abort the process. But this shouldn't be a common case.)

@alenhorvat
Copy link

Thank you @jogu . It's clear now.

If we want to make the process fail-proof, additional policy language should be defined and be part of the VC metadata that's shared between the wallet and the browser (I guess the wallet will need to know the type of the VCs user's wallets have + their presentation/sharing policies). I guess it will boil down to the password selector today.

If the browser API WG manages to define/agree upon these policies, it will importantly impact the ecosystems and their trust models. IMO it's an important feature (unlike passwords and passkeys, VCs are not domain-bound and risk of over-asking is real), so looking into evolution of the topic.

@jogu
Copy link
Collaborator Author

jogu commented Aug 27, 2024

If the browser API WG manages to define/agree upon these policies,

I think the browser API wg is currently leaving it to the underlying VC protocols (i.e. OID4VP) to define mechanisms like this.

@alenhorvat
Copy link

This implies that browser will only pass the information to the wallet and will not process it, or?

Is anywhere summarised what metadata the browser would have from the wallet and how that metadata is exchanged? Or the browser simply asks all the registered wallets to respond to a request?

@jogu
Copy link
Collaborator Author

jogu commented Aug 27, 2024

You can read about how the browser API implementation on Android currently works in detail here: https://github.com/WICG/digital-credentials/wiki/HOWTO%3A-Try-the-Prototype-API-in-Chrome-Android

The Android implementation is along the lines 'the browser [actually technically an OS component I think] simply asks all the registered wallets to respond to a request', but it does this in a way that the wallets run in a heavily sandboxed process so that doing this doesn't leak the user's request to every wallet (for privacy reasons).

@David-Chadwick
Copy link
Contributor

@jogu Your proposal 1. sounds good to me. This is an alternative to the TRAIN method that we implemented. Instead of the wallet going to the trust infrastructure to check that the RP's request is trustworthy, instead you are proposing that this snippet of the trust framework is signed by the root of trust and given back to the RP for it to include in its request to the wallet. Note however that the wallet will still need to make a callout to the trust infrastructure to ensure that the signed snippet has not been revoked since it was issued. Otherwise an RP that once was trustworthy and was given the signed snippet, but which later went rogue and whose snippet was revoked, could still request PII from any wallet that does not check the revocation status of the snippet. Alternatively the RP must go to the trust framework before making a request to the wallet, to obtain a short lived non-revocable snippet to include in its request to the wallet. The wallet then does not need to check the revocation status of the signed snippet.

@jogu
Copy link
Collaborator Author

jogu commented Aug 28, 2024

Exactly right @David-Chadwick - thanks.

@peppelinux
Copy link
Member

yes mates, the wallet needs to evaluate the trust with the RP, common checks like:

  • obtains RP public key to evaluate the signature validity (where not necessarly this should match with the one in the X.509 certificate used for TLS)
  • check the RP against any revocation from the federation (where it might require a foreign http request to some trusted lists or CRL resources or Federation API)

These two previous can be considered for granted despite any technical solution or more or less evolved trust framework.
These two previous requires the wallet to update its definitions about a fresh or expired, more or less known RP by fetching remote resources .

this is for RP authentication.

therefore we enter in the authorization realm, considering two implementation strategies:

  • embedded policies published within the credentials
  • verifiable manifests (metadata) publicly available and attested by one or more trusted third parties (many trust frameworks, multiple trust anchors and so on in an ideal decentralized wild world)

embedded policies reminds me the experience I had several years ago in the R&E implementation using SAML2 and the so called Entity Categories, in short a unique identifier that demonstrate an RP using a particular framework and therefore requesting a specific set of user attributes, without necessarly make them explicit in the request. There reason why embedded policies reminds me that is because using this approach i na rela world of large scale deployments we therefore will be forced to use RP categories to prevent the need to include in an issued credential the never endinf list of thousands of RP and therefore the requirement to update this list everytime a new RP joins the federation.

therefore embedded policies might add some encoded symbol pointing to some value and requirement to be configured in a trust framework and therefore implemented.

another important concern about the embedded policies is that if something changes in the list, or categories, of the allowed RP therefore this might require the revocation of all the already issued credentials for the update of the "embedded" policies. This might push us in the dark side of the embedded approach that is often used only for some particular, small and not scalable nor flexible approach.

the reason why I believe that using manifests such signed metadata is that:

  • it makes the information explicit and publicly accessible, discoverable. Here I want to mention the importance of having a transparent ecosystem where every entity can say whatever they want about themselves and according to the trusted third party involved for the compliance evaluation with that entity the policies are applied and their metadata changes, providing therefore the final, concrete, information in a specific context

  • any changes to the policies only applies to RP and without requiring any update to the RP (the trusted third party updates the policies and publishes it, to get these applied to all the RP metadata, even wihtout their consent!). At the same way this does not have any impacts on the previously issued credentials

@David-Chadwick
Copy link
Contributor

Concerning the contents of the signed snippet that the RP sends to the wallet, I would propose the presentation_definition_uri and an integrity protection attribute - see the W3C VCDM relatedResource property (https://www.w3.org/TR/vc-data-model-2.0/#integrity-of-related-resources) since this is both compact, resolvable by the wallet and integrity protected. The full presentation_definition will still need to be in the request so that the browser can determine which credential(s) is being requested without making a callout, but the wallet can check that the browser-selected credential is the same as the one that it would have selected using the signed snippet. In this way there does not need to be any complex comparisons of presentation definitions which @jogu referred to here #189 (comment)

@jogu
Copy link
Collaborator Author

jogu commented Sep 4, 2024

Running the match again as per @David-Chadwick's suggestion seems like an interesting solution, certainly one I hadn't considered.

It means acknowledging that the verifier can use a different PE in the request than the one that is ultimately used/permitted. I have a niggling feeling this introduced some possible issue, but given the end result is that the verifier should only receive a credential/claims that it is permitted to receive I'm struggling to see what the issue could be.

I think there is a possibility of misleading the user, or we need a very carefully described process for how this works, e.g. if the verifier is authorised to receive both name & DoB from driving licenses, and has a presentation_definition_uri that makes that query, but then the verifier makes a query that requests only the name then this mustn't result in a situation where the user thinks they've agreed to share their name only but then what actually happens is both their name & DoB get shared.

@jogu
Copy link
Collaborator Author

jogu commented Sep 4, 2024

@peppelinux For clarity, could you please clearly state whether you're in favour of option 1, or of option 2, or are suggesting a new third option?

@alenhorvat
Copy link

alenhorvat commented Sep 4, 2024

@jogu , can you please provide an example for your proposal 2?

In my understanding, 1 is the way information is passed from the RP to the wallet (which I believe we all agree upon), and 2 refers to how the information is expressed, i.e., as proposed by @David-Chadwick.

@David-Chadwick
Copy link
Contributor

What I am proposing is method 1. The RP sends the full presentation_definition that allows the browser to choose the credentials without any callout, whilst the signed snippet (which is probably a JWT) allows the wallet to verify that the RP is genuinely entitled to receive this PII.

@jogu

e.g. if the wallet is authorised to receive both name & DoB from driving licenses,

I think you meant verifier/RP in this paragraph when you wrote wallet. To answer your implied question, I think the rule that should be enforced by the wallet, is that whatever credential the browser chooses should be a subset of what the wallet determines is authorised by trust framework (via the signed snippet). Otherwise the wallet should reject the request (or defer to the user to ask if they want to release their PII to an unauthorised verifier)

@jogu
Copy link
Collaborator Author

jogu commented Sep 4, 2024

@alenhorvat The difference I see between 1 and 2 is that in 1 we can apply permissions at the matching stage then later verify they are correct permissions.

In 2, permissions are only applied after the user has picked a credential. David's suggestion is an example of 2 I believe, but it uses PE (fetched from a presentation_definition_uri) as what I called the 'permissions language'. (Although from later comments it seems like I've misunderstood what David meant.)

Another example of 2 (provided for clarifying what option 2 is, and I'm not suggesting it's an actual proposal we should take forward) would be defined say a permission language fetched from say https://centraldirectory.usa/.well-known//permissions that contains, say:

{
    "iso_mdl": {
        "given_name",
        "date_of_birth"
    }
}

(please don't nitpick the field names I picked :-) )

Then this would mean that verified with that client_id is permitted to fetch only ISO mdl and is only permitted to request the given_name and/or data_of_birth fields. This structure wouldn't be included in the request but would be fetched and evaluated by the wallet after the credential has been selected by the user.

@jogu
Copy link
Collaborator Author

jogu commented Sep 4, 2024

I think you meant verifier/RP in this paragraph when you wrote wallet.

@David-Chadwick I did, sorry - I've edited my comment to fix that.

@alenhorvat
Copy link

Thanks @jogu.

Option 1 is possible if there's an agreement on a common "policy language" and the RP passes the request query + proofs that it can make those requests. (*see below)

The example you showcased (for the 2nd case) could also be embedded in the request (and signed by a root authority responsible for that domain) - this I believe boils down to the suggestions in this discussion; Of course you'd need to put more information in a central registry (I personally would avoid having such a central registry for operational and privacy purposes, but it's up to the use case to decide).

  • I'm not following closely, but I remember there was a proposal where there is "query language" per "credential format" - having this makes option 1 impossible, since it becomes too complicated for the browsers/selectors to implement all the different options.

@David-Chadwick
Copy link
Contributor

@jogu I believe your example of 2. would need to be more complex to comply with GDPR as it will need to be per RP service and not per client_id (assuming the RP has the same client_id for the different services that it offers). So an RP which offers, say, a Read DB service and a Write DB service would probably want more PII for the latter than the former.

@peppelinux
Copy link
Member

@jogu according to my implementation experience with metadata policy language using openid federation I'd go for the option 2, with the evidence that in my vision option 2 applies on third party attested metadata.

using federation we apply policy upone the RP metadata, matching obviously its client_id

@jogu
Copy link
Collaborator Author

jogu commented Sep 11, 2024

@jogu I believe your example of 2. would need to be more complex to comply with GDPR as it will need to be per RP service and not per client_id (assuming the RP has the same client_id for the different services that it offers). So an RP which offers, say, a Read DB service and a Write DB service would probably want more PII for the latter than the former.

It almost certainly does need to be more complex, though I'm not sure that's a good example, I'm pretty sure we should only attach permissions to client_id and people shouldn't be sharing client_ids between services that have differing requirements (at least that would be the standard OAuth position). GDPR is I believed still satisfied anyway, as the client can still do data minimisation by asking for only some of the fields, or did you mean a different aspect of GDPR?

@David-Chadwick
Copy link
Contributor

The issue is not that the client can do data minimisation, but rather that the trust infrastructure ensures that the client's request does request minimum data.
Can we ensure that the RP uses a different client_id for each service?

@jogu
Copy link
Collaborator Author

jogu commented Sep 13, 2024

The issue is not that the client can do data minimisation, but rather that the trust infrastructure ensures that the client's request does request minimum data. Can we ensure that the RP uses a different client_id for each service?

You said it made it more complex to comply with GDPR though. To my knowledge GDPR doesn't require that the trust infrastructure ensures clients request minimum data, it's sufficient (to comply with GDPR) that the GDPR-regulated entity receiving the data is able to request only what it needs. (I'm not saying we shouldn't meet this requirement, just that it's not a requirement that comes from GDPR.)

@David-Chadwick
Copy link
Contributor

Being able to do something, and actually doing it are not the same thing. Probably most RPs can say that they are capable or requesting minimum data, but in reality they may try to collect more than is necessary. The user will not necessarily be able to differentiate between the two, which is where the trust framework steps in. The wallet can ensure that the RP acts properly because the trust framework will say what the minimum data is. If more is asked for the wallet can either refuse the request or ask the user if they want to provide this extra data (i.e. give user consent).

@jogu
Copy link
Collaborator Author

jogu commented Sep 13, 2024

We're in agreement I think. My only comment was that it's not required by law, I agree that it's a sensible requirement to consider.

@David-Chadwick
Copy link
Contributor

Surely asking for more than the minimum is breaking the law? Otherwise why have the law?

@jogu
Copy link
Collaborator Author

jogu commented Sep 13, 2024

The verifier is required by law not to ask for more than they need, they can already comply with the law in OID4VP today.

OID4VP is not required to provide a technical mechanism to allow a third party to try and force the verifier to comply with the law via technical mechanisms. It could choose to do so, but it is not required to do so by GDPR, and the lack of such a measure does not in any way mean that OID4VP cannot be used in countries where GDPR is in force. OAuth and OpenID Connect have no such measures to 'enforce GDPR' and are widely used in countries where GDPR is applicable.

(There may be other, more localised, laws that potentially require extra features.)

@David-Chadwick
Copy link
Contributor

Now I understand what you meant to say. Your statement "it's not required by law" was ambiguous. It could mean, the RP is not required by law (my interpretation) or OpenID4VP is not required by law (your intention). So we do agree now.

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

No branches or pull requests

4 participants