digitalbazaar / jsonld.js

A JSON-LD Processor and API implementation in JavaScript
https://json-ld.org/
Other
1.66k stars 195 forks source link

Excluding `@id` in the output with `@explicit: true` and `@id: null` won't work #454

Open kuzdogan opened 3 years ago

kuzdogan commented 3 years ago

I am using jsonld-signatures-bbs for selectively disclosing a credential. The library uses jsonld.js under the hood for framing.

In some of the cases, I want to exclude the id (alias for @id) of a child node, as it makes the document identifiable. In my code, I generate the JSON-LD frame, for instance, for the node journal as follows:

  {
  ...
    journal:
      journal.id || journal.name || journal.issn
        ? {
            '@explicit': true,
            id: journal.id ? {} : null,
            name: journal.name ? {} : null,
            issn: journal.issn ? {} : null,
          }
        : null,
  ...
}

If I exclude the id attribute (by assigning null) but try to include name I get

jsonld.SyntaxError: Invalid JSON-LD syntax; "@id" value an empty object or array of strings, if framing

I can exclude other attributes by assigning null but @id has an additional type check.

Is there a way to have the other attributes but exclude id (or @id) in the output? I checked the JSON-LD and Framing specs but couldn't find a rule enforcing output nodes to have an @id, it is said that "it is important that nodes have an identifier".

HanaeRateau commented 8 months ago

I'm having the same issue as you. Also, when not setting @id at all (omitting it into the frame), the id is still copied.

davidlehn commented 8 months ago

Can one of you provide a simple example? It's easier to help find bugs or workarounds with something that can be directly tested. Thanks.

HanaeRateau commented 8 months ago

Here is the json-ld that I want to frame:

{
        "@context": [
            "https://www.w3.org/2018/credentials/v1",
            "https://w3id.org/citizenship/v1",
            "https://w3id.org/security/bbs/v1"
        ],
        "id": "https://issuer.oidp.uscis.gov/credentials/83627465",
        "type": [
            "VerifiableCredential",
            "PermanentResidentCard"
        ],
        "issuer": "did:key:z5TcFJ7svtzqxRJ9zjGNBxmtAeUQ1F1dyhBsqbywN2V1vsX69bjPAiRPyTDtERHxEyqG6osjmp638MFhPtYUMTmEaTwiWqRW23kgRHc6NXPJE47k3DLCbs5Cickk9pPS9LK9chgFQyukDXKnSf9hyVZ5taxAVsTyGqyWeD3yfVeN8G48s9K4pdcHyEHPuPcZdPJiY8GUV",
        "identifier": "83627465",
        "name": "Permanent Resident Card",
        "description": "Government of Example Permanent Resident Card.",
        "issuanceDate": "2019-12-03T12:19:52Z",
        "expirationDate": "2029-12-03T12:19:52Z",
        "credentialSubject": {
            "type": [
                "PermanentResident",
                "Person"
            ],
            "id": "did:example:fneslf13834fefs",
            "givenName": "JOHN",
            "familyName": "SMITH",
            "gender": "Male",
            "image": "data:image/png;base64,iVBORw0KGgokJggg==",
            "residentSince": "2015-01-01",
            "lprCategory": "C09",
            "lprNumber": "999-999-999",
            "commuterClassification": "C1",
            "birthCountry": "Bahamas",
            "birthDate": "1958-07-17"
        },
        "proof": {
            "type": "BbsBlsSignature2020",
            ...
        }
    }

And here is the frame:

    {
        "@context": [
            "https://www.w3.org/2018/credentials/v1",
            "https://w3id.org/citizenship/v1",
            "https://w3id.org/security/bbs/v1"
        ],
        "type": [
            "VerifiableCredential",
            "PermanentResidentCard"
        ],
        "credentialSubject": {
            "@explicit": true,
            "type": [
                "PermanentResident",
                "Person"
            ],
            "givenName": {},
            "familyName": {},
            "gender": {}
        }
    }

With this frame, the id in credentialSubject still appears.

And when adding "id": null to the "credentialSubject" field I get an error from jsonld saying jsonld.SyntaxError: Invalid JSON-LD syntax; "@id" value an empty object or array of strings, if framing

HanaeRateau commented 8 months ago

Here is an example on the JSON-LD playground (here)

The id inside credentialSubject is still visible. Setting "id":null gives the error mentionned previously.

dlongley commented 8 months ago

I think even if the part of issue that is at the JSON-LD framing layer were resolved here, it wouldn't fully address all the concerns.

It's not going to be possible to selectively disclose claims without the id they are attached to using the BBS data integrity cryptosuite that is being standardized (and there are a number of potential data-mix attacks that would be need to be mitigated to support such an approach in the future). Instead, the original VC should omit any highly trackable PII ids in order to support unlinkable selective disclosure.

Another PRC example can be created showing how this is done -- which could also optionally include a confidenceMethod (https://w3c-ccg.github.io/confidence-method-spec/) that would allow for optional disclosure of a method for establishing additional confidence via countersignatures from the holder/presenter. Given some of the other modeling in the above example, I think it may be based off of an older version of the citizenship vocabulary spec.

Please note that just because an id field is supported in the PRC examples, that doesn't mean an issuer needs to use that field. IMO, more examples should be added to the citizenship vocabulary to help provide clarity there.

In short, a PRC could be issued that looks like more this (not a fully baked example):

{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://w3id.org/citizenship/v1",
    "https://w3id.org/security/data-integrity/v2"
  ],
  "type": [
    "VerifiableCredential",
    "PermanentResidentCard"
  ],
  "issuer": "did:key:z5TcFJ7svtzqxRJ9zjGNBxmtAeUQ1F1dyhBsqbywN2V1vsX69bjPAiRPyTDtERHxEyqG6osjmp638MFhPtYUMTmEaTwiWqRW23kgRHc6NXPJE47k3DLCbs5Cickk9pPS9LK9chgFQyukDXKnSf9hyVZ5taxAVsTyGqyWeD3yfVeN8G48s9K4pdcHyEHPuPcZdPJiY8GUV",
  "name": "Permanent Resident Card",
  "description": "Government of Example Permanent Resident Card.",
  "issuanceDate": "2019-12-01T00:00:00Z",
  "expirationDate": "2029-12-01T00:00:00Z",
  "credentialSubject": {
    "type": [
      "PermanentResident",
      "Person"
    ],
    // note: no `id` here
    "givenName": "JOHN",
    "familyName": "SMITH",
    "gender": "Male",
    "image": "data:image/png;base64,iVBORw0KGgokJggg==",
    "residentSince": "2015-01-01",
    // note: more up-to-date modeling per citizenship vocab
    "permanentResidentCard": {
      "type": "PermanentResidentCard",
      "identifier": "83627465",
      "lprCategory": "C09",
      "lprNumber": "999-999-999"
    },
    // selectively disclosable confidence method
    "confidenceMethod": {
      "type": "VerificationKeyConfirmation",
      "verificationMethod": "did:example:1234#some-key"
    }
  },
  "proof": {
    "type": "DataIntegrityProof",
    "verificationMethod": "https://example.edu/issuers/keys/3",
    "cryptosuite": "bbs-2023",
    "proofPurpose": "assertionMethod",
    "proofValue": "u2V0ChVhQp1smqO-Qmc-1KpNkShjevTeylTdVlpH_RNXeJ_cNniErWPbEWILvsoH5mYjnun5ibZHq0m7BEIaLv8sfMtLfcmgPj6tbAFwDWvEcbRWg7CFYQGWqCAnvTpL_Aao3aVCg5svdzFuvKqnvneA0UwaN0lagvGpWT7fCDGgcYPyNPKaCX94Xo06aTcSwOXgyGUbtN1xYYIU6t5wv20lVdESfzkYOFXTxIZa1HSBAZYWDyEgQ3A3ajzWX5qeFc3cwmnnrGUfJYwawgGLQAY3vBi3LTM2i3jCOPvxCEJALPIjK4tEmWb6uFjT4PWLlIEeTtYj_0yEv91ggsm9vw1PPlK6q8wQiw2i2joZ-OKkvHz7rDSxPYfmQNrqCbS9pc3N1YW5jZURhdGVnL2lzc3Vlcg"
  }
}

I'll also note that I don't think the mentioned library jsonld-signatures-bbs currently implements the W3C bbs-2023 cryptosuite that is undergoing standardization. You can take a look at this README for an example with an implementation that does:

https://github.com/digitalbazaar/vc?tab=readme-ov-file#issuing-a-verifiable-credential

EDIT:

Side note with more detail here on "how it works": the BBS signature is over N-many "messages" where each "message" is a claim in the VC. Each claim is a subject property value triple, where the subject value holds the id of the subject. This is the level of atomicity of what is signed (claims), so you can't break the claims up into individual components (subject, property, value) and disclose each separately -- and, as mentioned, enabling that would require more sophistry to avoid invalid recombinations by the presenter. Therefore, omitting the id allows that place to be assigned a "local ID" at signing time that is adequately shared across enough holders of the same VC type / expression (establishing group privacy for unlinkability) whilst preventing recombination attacks.

HanaeRateau commented 8 months ago

Thank you @dlongley for the detailed answer. I understand now why it would not be possible to hide the id. However, I'm confused about the confidence method mechanism. Isn't the verification method a unique identifier if we disclose it? And if we don't disclose it, it is of no use. I'm still learning all this so it may be a dumb question. I read the W3C draft on the confidence method but it did not help.

Otherwise, I'm looking into the digitalbazaar library. Thanks a lot.

dlongley commented 8 months ago

@HanaeRateau,

Thank you @dlongley for the detailed answer. I understand now why it would not be possible to hide the id. However, I'm confused about the confidence method mechanism. Isn't the verification method a unique identifier if we disclose it? And if we don't disclose it, it is of no use. I'm still learning all this so it may be a dumb question. I read the W3C draft on the confidence method but it did not help.

Your questions are good! The VC WG 2.0's timeline didn't allow the group to do work on the confidence method spec along with everything else the group needed to get done. Therefore, it got moved out to a separate draft document so it can be worked on once people free up finishing up the significant number of other documents the WG is producing at the moment. So it's not surprising that if you're not directly part of those discussions that you can't glean enough from the current state of that draft. That draft will continue to be worked on in the community against use cases (like the one above) to properly fill it out and bring it inline with the work people are doing in implementations.

Confidence methods are intended to be quite flexible, allowing lots of different ways of helping a verifier gain confidence about whether the presenter of a VC is a particular subject in the VC (that sort of thing). The above is just one example that might work for some use cases -- and you're right, it isn't an unlinkable way to provide that confidence. The point of the example was to show that it could be selectively disclosed; i.e., if that confidence method isn't needed, you don't have to show it (and its unambiguous identifier as you mention). However, if you have a use case where it's needed (i.e., where unlinkability won't be acceptable to the verifier for some kind of high value / highly identifying use case), it can be used.

Other confidence methods could potentially be created that provide more group privacy. How useful those are when a verifier really needs additional information beyond what is proven in the BBS derived VC (and encapsulated proof) is something that needs to be explored. Also, individual confidence methods can be selectively disclosed on their own -- so if one works for use case X and another works for use case Y -- you only need to disclose the one that works for the respective use case.

There's additional work happening on BBS w/pseudonyms and per-verifier linkability that can play a part in what guarantees a verifier gets when a BBS derived VC is presented. So there are a lot of "irons in the fire" in this space, if you will -- and we'll see what can fit into the timelines that the community and standards group(s) are currently working with. Major goals include just getting the interfaces and lower-level building blocks right so people can innovate and incubate with more use cases to see where interoperability can arise.

Otherwise, I'm looking into the digitalbazaar library. Thanks a lot.

Sure, I hope it helps with your use cases!

HanaeRateau commented 8 months ago

Thanks a lot for your reply. Being able to disclose the confidence method is an interesting feature I did not see. Do you happen to have any pointers about the current work on BBS that you mentioned (pseudonyms and per-verifier likability)?