Closed samuelgoto closed 4 days ago
I have suggested before that the initial query should be more abstract - eg The verifier needs proof-of-age or right-to-work as different creds can be selected by the user, before even the wallet is instantiated. Here is that proposal. https://docs.google.com/document/d/1n7HobJ6QTsNld5rn1uuIiNw0A__L44ug/edit
We can certainly try to cut this down to the bear minimum to get the user the ability to make a choice
08/26: Updated to avoid the duplication of the query language between the protocol layer and the platform layer, based on the feedback from the community in the DC CG call.
I posit that we should draw the line separating (a) credential selection and (b) wallet invocation: anything that helps (a) should be parsed, mediated and unbundled from anything that goes into (b) to remain, by design, unparsed and extensible.
I think it may be worth revisiting an early proposal: decouple the protocol's request
to the wallet from the parameters that are needed for credential/wallet selection.
To be concrete, here is an example of what a JS call looks like today, with the parts that I think browsers should and should not form an opinion on:
// Gets a CBOR with specific fields out of mobile driver's license as an mdoc
const controller = new AbortController();
const {protocol, data} = await navigator.identity.get({
signal: controller.signal,
digital: {
providers: [{
protocol: 'openid4vp',
request: {
// what benefit do we get by validating "response_type"?
response_type: 'vp_token',
// what benefit do we get by validating "nonce"?
nonce: 'gf69kepV+m5tGxUIsFtLi6pwg=',
// same with "client_metadata"
// NOTE(goto): it was noted on the 08/26 DC CG call that client_metadata may be something
// that would be useful for the browser to get, e.g. terms of services and privacy policies
client_metadata: {},
// on the other hand, "presentation_definition" is something that is worth looking at
presentation_definition: {
// presentation exchange, the query, omitted for brevity
}
}
}],
}
});
In this formulation, the request to the wallet (e.g. nonce
, response_type
) is bundled with the request to the OS (namely, presentation_definition
), so it forces the browser to open the entire request and inspect parts of it.
By comparison, invoking OpenID4VP through custom schemes, aside from all of its challenges, got one thing right: the integration with the OS to do wallet selection was entirely decoupled from the invocation after that.
So, one idea, is that, if we unbundled and decoupled the parts that browsers should absolutely form an opinion on, than we could make the rest of the request entirely opaque (by design).
For example:
// Gets a CBOR with specific fields out of mobile driver's license as an mdoc
const controller = new AbortController();
const {protocol, data} = await navigator.identity.get({
signal: controller.signal,
digital: {
providers: [{
protocol: 'openid4vp',
// request is opaque to the browser and doesn't get introspected
request: `__the__openid4vp__that_we_dont_introspect__asjjlkfsa__3920s__jklsfs__`,
// selector, on the other hand, is understood by the browser and affects credential selection
selector: {
// the query language that allows the OS to do credential selection
}
}],
}
});
There is probably a point to be made about making the selector
a query language that is browser-specific but protocol-agnostic, but that's a separate argument from the one I'd like to make (which is to create a clear delineation between what gets inspected and what doesn't).
NOTE: OpenID4VP's query language is currently Presentation Exchange, which in fact protocol agnostic. A new query language is being developed, which could also be adopted here.
selector
would also need to be extensible, since so much of the innovation is going to happen there, but the benefit here is that it makes it clear that the browser shouldn't get on the way of the protocol.
An immediate criticism here to this framing is that it is possible that
selector
would duplicatepresentation_definition
, and in doing so could be either wasteful (extra bytes) and/or attackable (e.g. what if the OS credential selector was inconsistent with later the permission that the wallet would gather?). Not having the duplicate would involve working with the OpenID4VP community to figure out how to avoid it.
The selector
would be passed to the wallet along with the request
.
The immediate benefit of this proposal, IMHO, is that it would make it very clear the delineation between the layers, with the OS doing credential selection but then getting out of way beyond that.
It's an interesting proposal.
Some initial thoughts:
I'm not immediately clear how it would work with signed requests (which currently sign over both the oid4vp bits and the selector bits), if we just remove selector
from the scope of the signature that might need some consideration as to how it changes the security posture (there have been separate suggestions that it should be possible to send signed requests where the query language part isn't signed but I don't think the DCP WG has formed a position on that yet).
I'm not sure if in some ecosystems more than the query language might be needed (or at least desirable) to do credential matching. At a minimum I'm not sure OID4VP makes it clear to people adopting & profiling the spec that any extensions that affect credential matching have to go in the query language.
Smart Digital Credential (SDC:) This is a suggestion to follow in the path of the Smart Health Card (SHC:) and allow for mobile credentials in the most inclusive manner possible. Here are the salient points:
I think this is a duplicate of #152, so closing this as a duplicate and taking this conversation there.
The Problem
There is a series of ongoing conversations around #152 at the protocol layer, #58 at the registry layer and https://github.com/WICG/digital-credentials/pull/156#discussion_r1727745625.
The tension is appearing at the degree of validation the browser should make: should the browser parse into a WebIDL the
request
field or not?On one hand, parsing the
request
gives the browser full visibility/control over the request but poses a serious problem evolving the protocol: because the WebIDL parser drops every unknown field, every extension to the protocol requires changing every browser before it could be used reliably (or worse: protocols abusingDOMString
s to pass opaque parameters). In addition to protocol extensibility, I think it is reasonable to think of security incidents that may require verifiers/holders to redeploy before it can get every browser to redeploy.On the other hand, not parsing the
request
gives theprotocol
extensibility but prevents the browser from (a) having visibility over what's being requested (and informing the user appropriately) and (b) passes a request to holders without any validation.A big part of the problem is that it is not clear which parts and why of the request should be inspected and which part shouldn't.
From what I've seen, as far as (a) is concerned, I think it is clear to me that the browser should have "at least" visibility over "what's being requested", specifically, the
presentation_definition
parameter of the OpenID4VPprotocol
, so that the browser can build a privacy risk engine. It is also possible thatclient_metadata
may give the browser some useful information too about the verifier that could be useful to construct prompts.But beyond that, I think it would be harmful to parse and validate other fields. Take
nonce
for example: there is nothing that a browser can do to validate whethernonce
is being used appropriately or not. Maybe one constructive exercise is go through the list of parameters and ask ourselves: which one of these does the browser have any reason to parse and validate?So, the problem is: where should we draw the line of what gets parsed and validated by the browser?