decentralized-identity / did-jwt-vc

Create and verify W3C Verifiable Credentials and Presentations in JWT format

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] When trying to verifyCredential or verifyPresentation, it fails with Error: wrong signature length.

ouoabcde opened this issue · comments

Current Behavior

I created vcJwt with createVerifiableCredentialJwt and vpJwt with createVerifiablePresentationJwt which are at did-jwt-vc module. And I tried to verifyCredential, verifyPresentation which are at did-resolver to verify vcJwt, vpJwt. But both fails at verifyJWT->verifyJWSDecoded->VerifierAlgorithm->verifyES256K->toSignatureObject (these functions are in did-jwt module.) with Error: wrong signature length.

Expected Behavior

verifyJWT should pass with vcJwt and vpJwt.

Failure Information

It's error stack is described at Current Behavior section. I debugged why it failed and found that vcJwt, vpJwt which are created by createVerifiableCredentialJwt and createVerifiablePresentationJwt had 65 length signature when they are decodedJwt. At toSignatureObject, it checks that rawSig.length is 65 when recoverable is true, and if it's 64 when it's not recoverable. But always passing recoverable = false which is default. vcJwt and vpJwt always failed verifying because their signature length were 65. So when I added toSignatureObject function call with recoverable = true at verifyES256K function, the verification passed to both of them.

Steps to Reproduce

For example, just for vcJwt and verifyCredential,

  1. Create vcJwt with createVerifiableCredentialJwt. (did-jwt-vc)
  2. Verify vcJwt with verifyCredential. (did-resolver)
  3. You'll get Error: wrong signature length. error message.

There might be some confusion about the algorithms used for the JWT.
What parameters are you using for createVerifiableCredentialJwt?

I used createVerifiableCredentialJwt(vcPayload, issuer). And my arguments were like below.

vcPayload

const myDid = "did:ethr:xxxx";
const claim = {
    test: {
        aaa: "aaa",
        bbb: "bbb",
    },
};

const vcPayload: JwtCredentialPayload = {
    sub: myDid,
    vc: {
        "@context": ["https://www.w3.org/2018/credentials/v1"],
        type: ["VerifiableCredential", "MyCustomCredential"],
        credentialSubject: claim,
    },
};

issuer

const issuer: Issuer = new EthrDID({
    identifier: "my ethereum address",
    privateKey: "my ethereum privatekey",
    chainNameOrId: 5777
}) as Issuer;

I see,
It appears that there is indeed a mismatch between the default signing algorithm that EthrDID uses for JWT (ES256K-R) and the one that createVerifiableCredentialJwt uses by default (ES256K) if no algorithm is specified.

I suppose that the bug here is that createVerifiableCredentialJwt simply assumes a default algorithm instead of complaining that there is none specified.

There are a few options to work around this issue.

  1. Let createVerifiableCredentialJwt know about the signer algorithm by specifying a header option:
const credential = await createVerifiableCredentialJwt(vcPayload, issuer, { header: { alg: 'ES256K-R' } })
  1. You can treat the EthrDID instance as an Issuer and make it provide an alg:
const issuer: Issuer = new EthrDID({/*...*/}) as Issuer;
issuer.alg = 'ES256K-R' // add this line

This will let createVerifiableCredentialJwt know which algorithm is actually in use.

  1. You can force your EthrDID instance to sign with a different signer (ES256K):
import { ES256KSigner } from "did-jwt";

const signer = ES256KSigner("my ethereum privatekey", false);
const issuer: Issuer = new EthrDID({
    identifier: "my ethereum address",
    signer: signer, // initialize with a signer instead of a private key
    chainNameOrId: 5777
}) as Issuer;

Thanks for the clear reason and the options to solve it. They all worked fine. So do you have plan to match the signing algorithm with EthrDID?