decentralized-identity / did-jwt-vc

Create and verify W3C Verifiable Credentials and Presentations in JWT format
Apache License 2.0
183 stars 44 forks source link

[BUG] Error: invalid_signature: no matching public key found #148

Closed JohnKHW closed 8 months ago

JohnKHW commented 8 months ago

Prerequisites

Please answer the following questions for yourself before submitting an issue.

YOU MAY DELETE THE PREREQUISITES SECTION if you're sure you checked all the boxes.

Current Behavior

The current behavior is using the the example code from README.md, but the network is the hardhat local network

  // Constructor in nestjs 
  constructor() {
    const { PRIVATE_KEY, NODE_URL, REGISTRY_ADDRESS } = process.env;

    this.provider = new ethers.JsonRpcProvider(NODE_URL);
    this.signer = new ethers.Wallet(PRIVATE_KEY, this.provider);

    this.ethereumDIDRegistry = EthereumDIDRegistry__factory.connect(
      REGISTRY_ADDRESS,
      this.signer,
    );

    this.resolver = new Resolver(
      getResolver({
        rpcUrl: NODE_URL,
        registry: REGISTRY_ADDRESS,
        networks: [
          {
            name: 'private',
            rpcUrl: NODE_URL,
            registry: REGISTRY_ADDRESS,
          },
        ],
      }),
    );

    this.did = new EthrDID({
      identifier: REGISTRY_ADDRESS,
      privateKey: PRIVATE_KEY,
      rpcUrl: NODE_URL,
      registry: REGISTRY_ADDRESS,
      chainNameOrId: 'private',
    });

    this.issuer = this.did as Issuer;
  }

  // issue VC JWT and upload the DID document to Smart Contract
  async issueCredential(address: string, privateKey: string): Promise<any> {
    const vc = {
      '@context': [
        'https://www.w3.org/2018/credentials/v1',
        'https://www.w3.org/ns/did/v1',
        'https://w3id.org/security/suites/secp256k1recovery-2020/v2',
      ],
      type: ['VerifiableCredential'],
      credentialSubject: {
        degree: {
          type: 'BachelorDegree',
          name: 'Baccalauréat en musiques numériques',
        },
      },
    };
    const did = address;
    const vcPayload: JwtCredentialPayload = {
      sub: `did:ethr:private:${address}`,
      nbf: 1562950282, // Not before timestamp
      vc,
    };

    const vcJwt = await createVerifiableCredentialJwt(vcPayload, this.issuer);

    const vcHash = this.hashVC(vc);
    const validity = 365 * 24 * 60 * 60; // Example: 1 year in seconds
    const txHash = await this.storeVCHash(did, vcHash, validity, privateKey);

    return { vcJwt, txHash };
  }
  // Verify JWT from input
  async verify(data: any) {
    const { jwt } = data;

    const verifiedVC = await verifyCredential(jwt, this.resolver);
    return verifiedVC;
  }

What is the current behavior?

Expected Behavior

Return JWT code after issue VC

{
    "vcJwt": "eyJhbGciOiJFUzI1NkstUiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fX0sInN1YiI6ImRpZDpldGhyOnByaXZhdGU6MHg3MDk5Nzk3MEM1MTgxMmRjM0EwMTBDN2QwMWI1MGUwZDE3ZGM3OUM4IiwibmJmIjoxNTYyOTUwMjgyLCJpc3MiOiJkaWQ6ZXRocjpwcml2YXRlOjB4ZTdmMTcyNUU3NzM0Q0UyODhGODM2N2UxQmIxNDNFOTBiYjNGMDUxMiJ9.r973UoWP9ncD_gxRvc3SDHJC6q3X41aTMaSFVgliOI4Xuxe0CQiBs3EQYN3pD2JhBPy_HtZzBYh-gDaeWAHDsQE",
    "txHash": "0xf1662635e66590eb7a6bc3b7f2abcc58558972bd322db7dc3e6a8fe988a70757"
}

verifyCredential should be able to return decoded JWT.

Please describe the behavior you are expecting

Failure Information

Error: invalid_signature: no matching public key found

Please help provide information about the failure.

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. use hardhat start the local node
    npx hardhat node
  2. deploy the erc1056 with the uups
    npx hardhat run --network localhost scripts/deploy_did_registry.ts
  3. paste the .env (the private key is from hardhat)
    NODE_URL=http://127.0.0.1:8545/
    NODE_ENV=development
    PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
    REGISTRY_ADDRESS=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512
    DATABASE_HOST=localhost
    PORT=3000
  4. start the nestjs
    npm run start:dev
  5. call the endpoint to the nestjs (the private key is from hardhat)
    http://localhost:3000/ekyc/issue-vc/0x70997970C51812dc3A010C7d01b50e0d17dc79C8/0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
  6. copy the JWT result and paste the JWT to localhost:3000/ekyc/verify in POST method
    {
    "jwt": "eyJhbGciOiJFUzI1NkstUiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fX0sInN1YiI6ImRpZDpldGhyOnByaXZhdGU6MHg3MDk5Nzk3MEM1MTgxMmRjM0EwMTBDN2QwMWI1MGUwZDE3ZGM3OUM4IiwibmJmIjoxNTYyOTUwMjgyLCJpc3MiOiJkaWQ6ZXRocjpwcml2YXRlOjB4ZTdmMTcyNUU3NzM0Q0UyODhGODM2N2UxQmIxNDNFOTBiYjNGMDUxMiJ9.r973UoWP9ncD_gxRvc3SDHJC6q3X41aTMaSFVgliOI4Xuxe0CQiBs3EQYN3pD2JhBPy_HtZzBYh-gDaeWAHDsQE"
    }
  7. you will get it
    Error: invalid_signature: no matching public key found

Environment Details

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

Failure Logs/Screenshots

[Nest] 15829  - 03/04/2024, 1:02:34 PM   ERROR [ExceptionsHandler] invalid_signature: no matching public key found
Error: invalid_signature: no matching public key found
    at verifyJWTDecoded (/file-directory/node_modules/did-jwt/src/JWT.ts:365:9)
    at verifyProof (/file-directory/node_modules/did-jwt/src/ConditionalAlgorithm.ts:16:12)
    at /file-directory/node_modules/did-jwt/src/JWT.ts:511:24
    at _catch (/file-directory/node_modules/did-jwt/lib/index.cjs:1456:18)
    at /file-directory/node_modules/did-jwt/src/JWT.ts:508:50
    at _for$1 (/file-directory/node_modules/did-jwt/src/JWT.ts:438:7)
    at /file-directory/node_modules/did-jwt/lib/index.cjs:1775:18
    at _temp7 (/file-directory/node_modules/did-jwt/lib/index.cjs:1801:8)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at DIDRegistryService.verify (/file-directory/src/modules/ekyc/didRegistry.service.ts:97:24)

Don't paste private keys anywhere public!

mirceanis commented 8 months ago

I noticed that you are setting the identifier of the DID to be the REGISTRY_ADDRESS. This is not correct. The identifier must correspond to the PRIVATE_KEY, at least initially. The identifier must be either the public key corresponding to the private key, or the equivalent ethereum address. This is most likely the cause of the failure.

this.did = new EthrDID({
      identifier: REGISTRY_ADDRESS, /// !!! this identifier must be either the public key or the ethereum address corresponding to the PRIVATE_KEY
      privateKey: PRIVATE_KEY,
      rpcUrl: NODE_URL,
      registry: REGISTRY_ADDRESS,
      chainNameOrId: 'private',
    });

Then, in your resolver configuration, you should either use the networks param, or the single network configuration, and it's wise to specify the chainID in the configuration as well.

getResolver({
        rpcUrl: NODE_URL,
        registry: REGISTRY_ADDRESS,
        chainId: <your hardhat chain ID here>, // add this
        name: 'private' // add this 
        // no longer need to add `networks`
      }),

Alternatively, you can specify only the networks, with a single entry:

getResolver({
    networks: [{
        rpcUrl: NODE_URL,
        registry: REGISTRY_ADDRESS,
        chainId: <your hardhat chain ID here>, // add this
        name: 'private' // add this
    ]}),
JohnKHW commented 8 months ago

Got it, I successed to run the code, thank you