Closed francesco-plt closed 1 year ago
It would be very helpful if you were able to link to a project that reproduces this error.
Where can I find the implementation of PolyGetResolver()
?
Can you paste some example DIDs/documents at least?
It would be very helpful if you were able to link to a project that reproduces this error. Where can I find the implementation of
PolyGetResolver()
? Can you paste some example DIDs/documents at least?
The code above is enough to reproduce the error. If you have a Polygon Wallet and you register a DID using the mumbai testnet, when resolving you end up with a DID document that looks like the following:
{
"@context": "https://w3id.org/did/v1",
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"verificationMethod": [
{
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"publicKeyBase58": "7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"
}
],
"authentication": [
"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
{
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"publicKeyBase58": "7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"
}
],
"assertionMethod": [
"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
{
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"publicKeyBase58": "7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"
}
]
}
And this is the code for PolyGetResolver
:
import { getResolver } from '@ayanworks/polygon-did-resolver';
export function PolyGetResolver() {
async function resolve(
did: string,
parsed: ParsedDID,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_unused: Resolvable,
options: DIDResolutionOptions
): Promise<DIDResolutionResult> {
// console.log(parsed)
// {method: 'mymethod', id: 'abcdefg', did: 'did:mymethod:abcdefg/some/path#fragment=123', path: '/some/path', fragment: 'fragment=123'}
const polyResolver = getResolver();
const resolver = new Resolver(polyResolver as ResolverRegistry);
try {
const didResolutionResult = await resolver.resolve(did) as any;
if (!didResolutionResult) {
throw new Error('Failed to resolve DID');
}
return {
didDocument: JSON.parse(didResolutionResult.didDocument),
didDocumentMetadata: didResolutionResult.didDocumentMetadata,
didResolutionMetadata: didResolutionResult.didResolutionMetadata
}
} catch (error) {
throw error;
}
}
return { polygon: resolve }
}
The function is built following the example for custom resolvers given by did-resolver README. If a resolver object is passed the PolyGetResolver
function, by calling resolve.resolve(...)
the DID document is retrieved correctly. The problem is that I am not able to verify correctly VCs because of the error I reported in the title of the issue.
I have not been able to pin down the issue to a specific step of the issuing/verifying process because I am not sure that I am even signing the credentials right:
const issuer = {
did: "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
alg: 'ES256K',
signer: ES256KSigner(hexToBytes(privateKey))
};
const vcJwt = await createVerifiableCredentialJwt(claim, issuer);
The code above looks fine in theory, but the VCs it produces are marked as invalid signature by jwt.io, for example the following one:
eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fX0sInN1YiI6ImRpZDpwb2x5Z29uOnRlc3RuZXQ6MHg5MjBCNTdFNjdjZWViNWRkMTc1MTNENWY1ODZlNDgyNzI3ZTI1NGQxIiwibmJmIjoxNTYyOTUwMjgyLCJpc3MiOiJkaWQ6cG9seWdvbjp0ZXN0bmV0OjB4RkFmQTZEZjg2NzBlZDAyRDY2RjFEQ2YzRDY1QTY2RTg3OUNmRTg0MyJ9.yVx01U0DlkqomOMDbHRQ31bjG8rzEPkMtZu5h7leDSdZ-kbd1qauzjzfiQKPxSEMlDGWJNAGepK71Tdt3mTNAA
When I try the resolver code you gave me I get an error in the polygon-did-resolver code:
[ERROR] default - Error occurred in resolve function Error: The DID document for the given DID was not found!
Here is my test project: https://github.com/mirceanis/ts-ethr-did/blob/main/src/didjwt-275.ts
Please post a project that manifests the error you reported (you can also use my project and make a PR there).
Here is my test project https://github.com/Mencucci/did-jwt-275 . In this project the resolution works, but the verification of the JWT generated in the messages above still fails. The error is different invalid_signature
. The project linked here shows the following output, including traceback, on my machine
C:\Program Files\nodejs\node.exe .\dist\app.js
resolutionResult
{
"didDocument": {
"@context": "https://w3id.org/did/v1",
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"verificationMethod": [
{
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"publicKeyBase58": "7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"
}
],
"authentication": [
"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
{
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"publicKeyBase58": "7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"
}
],
"assertionMethod": [
"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
{
"id": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",
"publicKeyBase58": "7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"
}
]
},
"didDocumentMetadata": {},
"didResolutionMetadata": {
"contentType": "application/did+ld+json"
}
}
Uncaught Error Error: invalid_signature: Signature invalid for JWT
at verifyES256K (d:\OneDrive - Politecnico di Milano\Polimi\A.A. 2022-2023\tesi\blockchain\ts-ethr-did-v4\node_modules\did-jwt-vc\node_modules\did-jwt\lib\index.module.js:718:22)
at verifyJWSDecoded (d:\OneDrive - Politecnico di Milano\Polimi\A.A. 2022-2023\tesi\blockchain\ts-ethr-did-v4\node_modules\did-jwt-vc\node_modules\did-jwt\lib\index.module.js:1284:47)
at <anonymous> (d:\OneDrive - Politecnico di Milano\Polimi\A.A. 2022-2023\tesi\blockchain\ts-ethr-did-v4\node_modules\did-jwt-vc\node_modules\did-jwt\lib\index.module.js:1031:30)
at processTicksAndRejections (internal/process/task_queues:95:5)
Process exited with code 1
Important note: polygon-did-resolver
has a dependency on "ethers": "5.4.7"
, exact version. This is not specified anywhere, but earlier and later versions cause the resolution to fail. npm i
is recommended before running the project or in case of DID resolution errors.
I am Francesco's partner in this project, we've worked on this together. This happens to be the first working minimal example of this error. Thank you for your help
It looks like that the verification process fails because of a problem in the verifyES256K
function inside did-jwt
. The function tries to retrieve the public key of the signer from its DID document, part of which is contained in a variable called fullPublicKeys
. The following code snippet returns false
and the verification process fails:
let signer = fullPublicKeys.find(pk => {
try {
const pubBytes = extractPublicKeyBytes(pk);
const a = secp256k1.keyFromPublic(pubBytes);
return a.verify(hash, sigObj);
} catch (err) {
return false;
}
});
If I hardcode the public key of the signer into the library as follows:
signer = "7Lnm1ezAQuGXLZH9ruHbWGo6P6t4F1yqm8UaNATW53MFDoGgxABiupKMNtPz8WDCr4w3bdW7ukkY9cpdh6VvTTMDibgs4";
The verification is succesful:
{"verified":true,"payload":{"vc":{"@context":["https://www.w3.org/2018/credentials/v1"],"type":["VerifiableCredential"],"credentialSubject":{"degree":{"type":"BachelorDegree","name":"Baccalauréat en musiques numériques"}}},"sub":"did:polygon:testnet:0x920B57E67ceeb5dd17513D5f586e482727e254d1","nbf":1562950282,"iss":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843"},"didResolutionResult":{"didDocument":{"@context":"https://w3id.org/did/v1","id":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843","verificationMethod":[{"id":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1","type":"EcdsaSecp256k1VerificationKey2019","controller":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843","publicKeyBase58":"7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"}],"authentication":["did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",{"id":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1","type":"EcdsaSecp256k1VerificationKey2019","controller":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843","publicKeyBase58":"7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"}],"assertionMethod":["did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843",{"id":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843#key-1","type":"EcdsaSecp256k1VerificationKey2019","controller":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843","publicKeyBase58":"7Lnm1exz9mqBpRfjiafdQS1N9PmkB9vhjApyWZmYaudUzstCKjzBsG9sAjxPdSmFYFZ9i7d3PsfzdSMWsquvhpBNeFTNf"}]},"didDocumentMetadata":{},"didResolutionMetadata":{"contentType":"application/did+ld+json"}},"issuer":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843","signer":"7Lnm1ezAQuGXLZH9ruHbWGo6P6t4F1yqm8UaNATW53MFDoGgxABiupKMNtPz8WDCr4w3bdW7ukkY9cpdh6VvTTMDibgs4","jwt":"eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fX0sInN1YiI6ImRpZDpwb2x5Z29uOnRlc3RuZXQ6MHg5MjBCNTdFNjdjZWViNWRkMTc1MTNENWY1ODZlNDgyNzI3ZTI1NGQxIiwibmJmIjoxNTYyOTUwMjgyLCJpc3MiOiJkaWQ6cG9seWdvbjp0ZXN0bmV0OjB4RkFmQTZEZjg2NzBlZDAyRDY2RjFEQ2YzRDY1QTY2RTg3OUNmRTg0MyJ9.yVx01U0DlkqomOMDbHRQ31bjG8rzEPkMtZu5h7leDSdZ-kbd1qauzjzfiQKPxSEMlDGWJNAGepK71Tdt3mTNAA","policies":{},"verifiableCredential":{"credentialSubject":{"degree":{"type":"BachelorDegree","name":"Baccalauréat en musiques numériques"},"id":"did:polygon:testnet:0x920B57E67ceeb5dd17513D5f586e482727e254d1"},"issuer":{"id":"did:polygon:testnet:0xFAfA6Df8670ed02D66F1DCf3D65A66E879CfE843"},"type":["VerifiableCredential"],"@context":["https://www.w3.org/2018/credentials/v1"],"issuanceDate":"2019-07-12T16:51:22.000Z","proof":{"type":"JwtProof2020","jwt":"eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fX0sInN1YiI6ImRpZDpwb2x5Z29uOnRlc3RuZXQ6MHg5MjBCNTdFNjdjZWViNWRkMTc1MTNENWY1ODZlNDgyNzI3ZTI1NGQxIiwibmJmIjoxNTYyOTUwMjgyLCJpc3MiOiJkaWQ6cG9seWdvbjp0ZXN0bmV0OjB4RkFmQTZEZjg2NzBlZDAyRDY2RjFEQ2YzRDY1QTY2RTg3OUNmRTg0MyJ9.yVx01U0DlkqomOMDbHRQ31bjG8rzEPkMtZu5h7leDSdZ-kbd1qauzjzfiQKPxSEMlDGWJNAGepK71Tdt3mTNAA"}}}
The problem arises from the following portion of the source code of did-jwt
:
https://github.com/decentralized-identity/did-jwt/blob/d898aa613a856cc7d3b2f2cc70ce4d8452b4e667/src/VerifierAlgorithm.ts#L106-L112
If I hardcode the public key of the signer into the library as follows:
signer = "7Lnm1ezAQuGXLZH9ruHbWGo6P6t4F1yqm8UaNATW53MFDoGgxABiupKMNtPz8WDCr4w3bdW7ukkY9cpdh6VvTTMDibgs4";
Can you clarify what you mean by hardcoding the signer?
I was able to debug what's going on using @Mencucci 's project.
It seems that the publicKeyBase58
you are returning in the resolver is incorrect.
For a Secp256k1 key it should represent an encoding of the raw public key bytes which is 33 bytes long in compressed form, or 65 bytes in uncompressed form.
The publicKeyBase58
value you are returning decodes to 68 bytes.
After further investigation, I realized that the 68 bytes represent the base58btc
encoding of the utf-8
encoding of the hex
encoded compressed public key prefixed with 0x
.
I know.. right?
It seems that somewhere in the pipeline a publicKeyHex
is getting encoded to base58 instead of the actual bytes of the public key. And, if I interpret the key according to this incorrect encoding, then verification works.
Please check your code again for the step where you compute the publicKeyBase58
that goes into the DID document.
I will close this issue as it doesn't represent a bug in did-jwt.
Current Behavior
I cannot use
did-jwt-vc
library to verify VCs because the traceback reports the following error happening indid-jwt
:Expected Behavior
The verification process should work as usual even if I am using a custom
Issuer
in thecreateVerifiableCredentialJwt
function and a customgetResolver
function to initialize theResolver
object used in the following function callconst verificationStatus = await verifyCredential(vcJwt, resolver);
. This is weird because the errorError: no_suitable_keys: DID document for did:polygon:testnet:0x... does not have public keys for ES256K-R
does not make sense: if I do not use customIssuer
andgetResolver
the process of verification ideally works fine without errors. The problem is that my implementation in code needs those objects to be customizable.Failure Information
Steps to Reproduce
Step 1: create a VC using a custom issuer
Both the
issuer
and thesub
of the VC are DIDs with methodpolygon:testnet
(e.g.did:polygon:testnet:0x...
).Step 2: verify the VC using a custom resolver
Note: the custom resolver works correctly, if I run:
The DID document is returned correctly.