Sphereon-Opensource / OID4VC

OpenID for Verifiable Credentials - modules for issuers, holders and RPs
Apache License 2.0
68 stars 20 forks source link

Bug: sd-jwt-vc issuing fails with missing hasher #116

Closed cre8 closed 4 months ago

cre8 commented 5 months ago

I updated from draf 11 to draft 13 using the sd-jwt-vc credentials. My credentialSignerCallback implementation returned a compact jwt as string. But then I am getting this response:

endErrorResponse (500): {"error":"invalid_request","error_description":"Hasher implementation is required to decode SD-JWT"}

error message: Hasher implementation is required to decode SD-JWT
error object: {}
Original error stack (if any) and REST API error stack:

Error: Hasher implementation is required to decode SD-JWT
    at Function.decodeVerifiableCredential (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+ssi-types@0.25.1-unstable.87\node_modules\@sphereon\ssi-types\src\mapper\credential-mapper.ts:116:15)
    at Function.toUniformCredential (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+ssi-types@0.25.1-unstable.87\node_modules\@sphereon\ssi-types\src\mapper\credential-mapper.ts:472:38)
    at VcIssuer.<anonymous> (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+oid4vci-issuer@0.12.0\node_modules\@sphereon\oid4vci-issuer\lib\VcIssuer.ts:602:38)
    at Generator.next (<anonymous>)
    at fulfilled (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+oid4vci-issuer@0.12.0\node_modules\@sphereon\oid4vci-issuer\dist\VcIssuer.js:28:58)

The const decoded = CredentialMapper.decodeVerifiableCredential(original) gets no hasher passed, so I returned a decoded sdjwt like:

    const credentialSignerCallback: CredentialSignerCallback<
      DIDDocument
    > = async (args) => {
      const jwt = await sdjwt.issue<SdJwtVcPayload>(
        args.credential as unknown as SdJwtVcPayload,
        this.issuerDataService.getDisclosureFrame(
          args.credential.vct as string
        ),
        { header: { kid: await this.keyService.getKid() } }
      );
      await this.credentialsService.create({
        value: jwt,
        id: args.credential.jti as string,
      });
      return decodeSdJwtVc(jwt, digest) as unknown as Promise<CompactSdJwtVc>;
    };

But then then it fails earlier:

    error message: Converting SD-JWT VC to uniform VC is not supported.
error object: {}
Original error stack (if any) and REST API error stack:

Error: Converting SD-JWT VC to uniform VC is not supported.
    at Function.toUniformCredential (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+ssi-types@0.25.1-unstable.87\node_modules\@sphereon\ssi-types\src\mapper\credential-mapper.ts:461:13)
    at VcIssuer.<anonymous> (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+oid4vci-issuer@0.12.0\node_modules\@sphereon\oid4vci-issuer\lib\VcIssuer.ts:602:38)
    at Generator.next (<anonymous>)
    at fulfilled (C:\Users\mollik\Projects\credhub\node_modules\.pnpm\@sphereon+oid4vci-issuer@0.12.0\node_modules\@sphereon\oid4vci-issuer\dist\VcIssuer.js:28:58)

I would assume that the hasher function pass is missing in the function call, or do you have a better return type for the CredentialSignerCallback

nklomp commented 5 months ago

Just to confirm. This was working with the previous version of the VCI lib that only supported up to Draft 11?

cre8 commented 5 months ago

Just to confirm. This was working with the previous version of the VCI lib that only supported up to Draft 11?

Yes, when updating the packages from 0.10.3to 0.12.0, see https://github.com/openwallet-foundation-labs/credhub/pull/70/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519

nklomp commented 5 months ago

Okay thanks, we will have a look

cre8 commented 5 months ago

Found it: https://github.com/Sphereon-Opensource/OID4VCI/commit/c4d34836fb4923c98e7743221978c902c8427f2a#diff-31f517f923d6832c3f5a869e5700893bde981414d8f583fac56e56cb520edca5R588

You wanted to uniform the credential here for a generalized event. But when it's an sd-jwt string encoded, the toUniFormCredential function needs the hasher.

I am not sure if it's better to let the CredentialSignerCallback return a decoded credential and not of type string to avoid this scenario. But encoding and decoding and encoding does not seems to be a good solution :D

cre8 commented 5 months ago

I would suggest to just pass the credential "as is" in the event without specific information like issuer. Parsing the credentials to get specific attributes will increase the complexity.

cre8 commented 5 months ago

A patch like this works fine:

diff --git a/dist/VcIssuer.js b/dist/VcIssuer.js
index 31db1854f9b56f46cb736da64cc345a183a1b16b..30386be728cf06b5481aa90b6cbdee61e58dde23 100644
--- a/dist/VcIssuer.js
+++ b/dist/VcIssuer.js
@@ -471,15 +471,15 @@ class VcIssuer {
                 throw new Error(oid4vci_common_1.ISSUER_CONFIG_ERROR);
             }
             const credential = issuerCallback ? yield issuerCallback(opts) : yield this._credentialSignerCallback(opts);
-            const uniform = ssi_types_1.CredentialMapper.toUniformCredential(credential);
-            const issuer = uniform.issuer ? (typeof uniform.issuer === 'string' ? uniform.issuer : uniform.issuer.id) : '<unknown>';
+            // const uniform = ssi_types_1.CredentialMapper.toUniformCredential(credential);
+            // const issuer = uniform.issuer ? (typeof uniform.issuer === 'string' ? uniform.issuer : uniform.issuer.id) : '<unknown>';
             // TODO: Create builder
             events_1.EVENTS.emit(events_1.CredentialEventNames.OID4VCI_CREDENTIAL_ISSUED, {
                 eventName: events_1.CredentialEventNames.OID4VCI_CREDENTIAL_ISSUED,
                 id: (0, uuid_1.v4)(),
                 data: credential,
                 // TODO: Format, request etc
-                initiator: issuer !== null && issuer !== void 0 ? issuer : '<unknown>',
+                // initiator: issuer !== null && issuer !== void 0 ? issuer : '<unknown>',
                 initiatorType: ssi_types_1.InitiatorType.EXTERNAL,
                 system: ssi_types_1.System.OID4VCI,
                 subsystem: ssi_types_1.SubSystem.VC_ISSUER,
cre8 commented 4 months ago

Closing this since it seems to be fixed in 0.14.0