digitalcredentials / vc

JavaScript implementation of W3C Verifiable Credentials standard
BSD 3-Clause "New" or "Revised" License
4 stars 4 forks source link

Credential doesn't have a log #6

Closed lautom36 closed 11 months ago

lautom36 commented 1 year ago

When verifying the attached credential on verifier plus the returned verificationResult does not have a log. revokedCredential.zip

sethduffin commented 1 year ago

I'm seeing the same thing for the Learner Credential Wallet.

Hitting vc.verifyCredential with the revoked credential @lautom36 attached above returns the following response:

{
  "verified": false,
  "results": [
    {
      "proof": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://w3id.org/security/suites/ed25519-2020/v1",
          "https://w3id.org/dcc/v1",
          "https://w3id.org/vc/status-list/2021/v1"
        ],
        "type": "Ed25519Signature2020",
        "created": "2022-08-19T06:58:29Z",
        "verificationMethod": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC#z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
        "proofPurpose": "assertionMethod",
        "proofValue": "z33Wy3kvx8UEoPHdQWYHVCXAjW19AZpA88NnikwfJqcH9oNmHyqSkt6wiVS31ewytAX7m2vneVEm8Awo4xzqKHYUp"
      },
      "verified": false,
      "error": {
        "name": "Error",
        "message": "Invalid signature.",
        "stack": "..."
      }
    }
  ],
  "error": {
    "name": "VerificationError",
    "errors": [
      {
        "name": "Error",
        "message": "Invalid signature.",
        "stack": "..."
      }
    ]
  }
}

The response does not contain a log property. It does return Invalid signature as the error message, but I imagine we don't want to parse from that for the credential status UI checks, and use the the log mapping instead.

dmitrizagidulin commented 1 year ago

@lautom36

When verifying the attached credential on verifier plus the returned verificationResult does not have a log. revokedCredential.zip

Ok, so, there's a couple things going on here. The first was -- for bizarre reasons, when verification was encountering a TypeError, it came back like this:

{
  "verified": false,
  "results": [
     // ... results were here
  ],
  "error": {}
}

Notice the empty object for the error property -- apparently, TypeError JSON.stringifies to {}.

This behavior is changed in PR https://github.com/digitalcredentials/vc/pull/8, published as v4.2.0. Now, when a TypeError is encountered, it just re-throws it instead of adding it to the results log. I believe this is the desired behavior specifically in the case of type errors -- other VC-related errors will go into the error log as usual.

So after PR 8, the actual error surfaced: TypeError: A "checkStatus" function must be given to verify credentials with "credentialStatus". Ok, so far so good, that's expected. And when I passed in checkStatus, as required, the VC from your revokedCredential.zip verified correctly (flagging the revoked status). To reproduce:

import { checkStatus } from '@digitalcredentials/vc-status-list';
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020';
import { securityLoader } from '@digitalcredentials/security-document-loader';
import vc from '@digitalcredentials/vc';

// From the zipped file
const revokedCredential = {
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1",
    "https://w3id.org/dcc/v1",
    "https://w3id.org/vc/status-list/2021/v1"
  ],
  "type": [
    "VerifiableCredential",
    "Assertion"
  ],
  "issuer": {
    "id": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
    "name": "Example University",
    "url": "https://cs.example.edu",
    "image": "https://user-images.githubusercontent.com/947005/133544904-29d6139d-2e7b-4fe2-b6e9-7d1022bb6a45.png"
  },
  "issuanceDate": "2020-08-16T12:00:00.000+00:00",
  "credentialSubject": {
    "id": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
    "name": "Kayode Ezike",
    "hasCredential": {
      "type": [
        "EducationalOccupationalCredential"
      ],
      "name": "GT Guide",
      "description": "The holder of this credential is qualified to lead new student orientations."
    }
  },
  "expirationDate": "2025-08-16T12:00:00.000+00:00",
  "credentialStatus": {
    "id": "https://digitalcredentials.github.io/credential-status-playground/JWZM3H8WKU#3",
    "type": "StatusList2021Entry",
    "statusPurpose": "revocation",
    "statusListIndex": 3,
    "statusListCredential": "https://digitalcredentials.github.io/credential-status-playground/JWZM3H8WKU"
  },
  "proof": {
    "type": "Ed25519Signature2020",
    "created": "2022-08-19T06:58:29Z",
    "verificationMethod": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC#z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
    "proofPurpose": "assertionMethod",
    "proofValue": "z33Wy3kvx8UEoPHdQWYHVCXAjW19AZpA88NnikwfJqcH9oNmHyqSkt6wiVS31ewytAX7m2vneVEm8Awo4xzqKHYUp"
  }
}

const documentLoader = securityLoader().build()

    const suite = new Ed25519Signature2020();
    const result = await vc.verifyCredential({
      credential: revokedCredential,
      suite,
      documentLoader,
      checkStatus
    });

    console.log(JSON.stringify(result, null, 2))

Resulted in:

{
  "verified": false,
  "results": [
    {
      "proof": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://w3id.org/security/suites/ed25519-2020/v1",
          "https://w3id.org/dcc/v1",
          "https://w3id.org/vc/status-list/2021/v1"
        ],
        "type": "Ed25519Signature2020",
        "created": "2022-08-19T06:58:29Z",
        "verificationMethod": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC#z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
        "proofPurpose": "assertionMethod",
        "proofValue": "z33Wy3kvx8UEoPHdQWYHVCXAjW19AZpA88NnikwfJqcH9oNmHyqSkt6wiVS31ewytAX7m2vneVEm8Awo4xzqKHYUp"
      },
      "verified": true,
      "verificationMethod": {
        "@context": "https://w3id.org/security/suites/ed25519-2020/v1",
        "id": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC#z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
        "type": "Ed25519VerificationKey2020",
        "controller": "did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC",
        "publicKeyMultibase": "z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC"
      },
      "purposeResult": {
        "valid": true
      },
      "log": [
        {
          "id": "expiration",
          "valid": true
        },
        {
          "id": "valid_signature",
          "valid": true
        },
        {
          "id": "issuer_did_resolves",
          "valid": true
        },
        {
          "id": "revocation_status",
          "valid": false
        }
      ]
    }
  ],
  "statusResult": {
    "verified": false,
    "error": {
      "cause": {}
    }
  },
  "log": [
    {
      "id": "expiration",
      "valid": true
    },
    {
      "id": "valid_signature",
      "valid": true
    },
    {
      "id": "issuer_did_resolves",
      "valid": true
    },
    {
      "id": "revocation_status",
      "valid": false
    }
  ]
}
dmitrizagidulin commented 1 year ago

@sethduffin - so, I believe it's now giving the correct/expected behavior (see previous comment). I'm puzzled why you're encountering an Invalid Signature error... Can you paste the exact credential and code to reproduce?

sethduffin commented 1 year ago

@dmitrizagidulin Thanks for looking into this! With the latest version of the library, I'm no longer seeing the Invalid Signature error for the attached credential above.

However, I found a potentially related issue with the following JFF credential:

Deep Link ``` 'dccrequest://request?issuer=https%3A%2F%2Fissuer.example.com&vc_request_url=https://verify.dcconsortium.org/request/credential&challenge=ke12345678-0001&auth_type=bearer' ```
Credential JSON ```json { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://purl.imsglobal.org/spec/ob/v3p0/context.json", "https://w3id.org/security/suites/ed25519-2020/v1" ], "id": "urn:uuid:a63a60be-f4af-491c-87fc-2c8fd3007a58", "type": [ "VerifiableCredential", "OpenBadgeCredential" ], "name": "JFF x vc-edu PlugFest 2 Interoperability", "issuer": { "type": [ "Profile" ], "id": "did:key:z6MkpMKDNykeb9hSQkz8RWCRrqHoo3y56gQb3Lj78xWgkNZh", "name": "Jobs for the Future (JFF)", "url": "https://www.jff.org/", "image": "https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/images/JFF_LogoLockup.png" }, "issuanceDate": "2020-08-16T12:00:00.000+00:00", "credentialSubject": { "type": [ "AchievementSubject" ], "id": "did:key:z6MkoKKunipwyPQLwzc4X3n6zeaNXFU37it8HX6m6TP1zVMa", "achievement": { "id": "urn:uuid:bd6d9316-f7ae-4073-a1e5-2f7f5bd22922", "type": [ "Achievement" ], "name": "JFF x vc-edu PlugFest 2 Interoperability", "description": "This credential solution supports the use of OBv3 and w3c Verifiable Credentials and is interoperable with at least two other solutions. This was demonstrated successfully during JFF x vc-edu PlugFest 2.", "criteria": { "narrative": "Solutions providers earned this badge by demonstrating interoperability between multiple providers based on the OBv3 candidate final standard, with some additional required fields. Credential issuers earning this badge successfully issued a credential into at least two wallets. Wallet implementers earning this badge successfully displayed credentials issued by at least two different credential issuers." }, "image": { "id": "https://w3c-ccg.github.io/vc-ed/plugfest-2-2022/images/JFF-VC-EDU-PLUGFEST2-badge-image.png", "type": "Image" } } }, "expirationDate": "2025-08-16T12:00:00.000+00:00", "proof": { "type": "Ed25519Signature2020", "created": "2022-10-25T20:36:28Z", "verificationMethod": "did:key:z6MkpMKDNykeb9hSQkz8RWCRrqHoo3y56gQb3Lj78xWgkNZh#z6MkpMKDNykeb9hSQkz8RWCRrqHoo3y56gQb3Lj78xWgkNZh", "proofPurpose": "assertionMethod", "proofValue": "z634bNRQFF1h8RafdMY8cAs7mGyR3ygj6WcqdKLGQfuwpHByLVe7Uxs7aNdPdNGHXgqZHC14ZvBXPYrF5fNezj9LT" } } ```
Verify Response ```json { "verified": false, "results": [ { "proof": { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/ed25519-2020/v1", "https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/jff-vc-edu-plugfest-1-context.json" ], "type": "Ed25519Signature2020", "created": "2022-10-20T22:27:24Z", "verificationMethod": "did:key:z6MkpMKDNykeb9hSQkz8RWCRrqHoo3y56gQb3Lj78xWgkNZh#z6MkpMKDNykeb9hSQkz8RWCRrqHoo3y56gQb3Lj78xWgkNZh", "proofPurpose": "assertionMethod", "proofValue": "z2k93dQ5UmGY6pqLGhPXG8cTPyxFcSB8ku4obGaH7z8Th1b29e4iL4hedZX29eqgy6btJB4ZH2TwbpXxRpo2Vsq5m" }, "verified": false, "error": { "name": "jsonld.InvalidUrl", "details": { "code": "loading remote context failed", "url": "https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/jff-vc-edu-plugfest-1-context.json", "cause": { "name": "Error", "message": "Document not found in document loader: https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/jff-vc-edu-plugfest-1-context.json", "stack": "..." } }, "message": "Dereferencing a URL did not result in a valid JSON-LD object. Possible causes are an inaccessible URL perhaps due to a same-origin policy (ensure the server uses CORS if you are using client-side JavaScript), too many redirects, a non-JSON response, or more than one HTTP Link Header was provided for a remote context.", "stack": "..." } } ], "error": { "name": "VerificationError", "errors": [ { "name": "jsonld.InvalidUrl", "details": { "code": "loading remote context failed", "url": "https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/jff-vc-edu-plugfest-1-context.json", "cause": { "name": "Error", "message": "Document not found in document loader: https://w3c-ccg.github.io/vc-ed/plugfest-1-2022/jff-vc-edu-plugfest-1-context.json", "stack": "..." } }, "message": "Dereferencing a URL did not result in a valid JSON-LD object. Possible causes are an inaccessible URL perhaps due to a same-origin policy (ensure the server uses CORS if you are using client-side JavaScript), too many redirects, a non-JSON response, or more than one HTTP Link Header was provided for a remote context.", "stack": "..." } ] } } ```


If this error is the result of an outdated credential format (or other related attributes), then I am ok closing this issue.

For the time being (and to handle potential future cases), I'm adding logic to LCW to display a generic verification error message instead of the checkmark list, in the event a verify response does not contain a log value (the response's real error will be logged to the console).

@lautom36 we'll probably want to add this to WebVerifier+ as well.

kayaelle commented 11 months ago

Closing.