From aa95af00ce755ae0022b4b17ae8c996e0b970842 Mon Sep 17 00:00:00 2001 From: Mircea Nistor Date: Fri, 26 Jan 2024 22:02:52 +0100 Subject: [PATCH] fix(credential-ld): let verifiers use all supported verification methods (#1331) The `VeramoLdSignature.getSupportedVerificationType()` can now return `string[]` as well as `string` fixes #1329 --- __tests__/shared/verifiableDataLD.ts | 3 ++- .../credential-ld/src/ld-credential-module.ts | 16 ++++++++------- packages/credential-ld/src/ld-suite-loader.ts | 20 +++++++++---------- packages/credential-ld/src/ld-suites.ts | 2 +- .../EcdsaSecp256k1RecoverySignature2020.ts | 4 +++- .../src/suites/Ed25519Signature2018.ts | 7 ++++--- .../src/suites/Ed25519Signature2020.ts | 7 ++++--- .../src/suites/JsonWebSignature2020.ts | 5 +++-- 8 files changed, 36 insertions(+), 28 deletions(-) diff --git a/__tests__/shared/verifiableDataLD.ts b/__tests__/shared/verifiableDataLD.ts index 8f3d127d5..118e3892b 100644 --- a/__tests__/shared/verifiableDataLD.ts +++ b/__tests__/shared/verifiableDataLD.ts @@ -230,7 +230,8 @@ export default (testContext: { // Check credential: expect(verifiableCredential).toHaveProperty('proof') - expect(verifiableCredential).toHaveProperty('proof.jws') + const proofValue = verifiableCredential.proof.jws ?? verifiableCredential.proof.proofValue + expect(proofValue).toBeDefined() expect(verifiableCredential.proof.verificationMethod).toEqual( `${didKeyIdentifier.did}#${didKeyIdentifier.did.substring( didKeyIdentifier.did.lastIndexOf(':') + 1, diff --git a/packages/credential-ld/src/ld-credential-module.ts b/packages/credential-ld/src/ld-credential-module.ts index 41802427c..364c999db 100644 --- a/packages/credential-ld/src/ld-credential-module.ts +++ b/packages/credential-ld/src/ld-credential-module.ts @@ -36,10 +36,7 @@ export class LdCredentialModule { this.ldSuiteLoader = options.ldSuiteLoader } - getDocumentLoader( - context: IAgentContext, - attemptToFetchContexts: boolean = false, - ) { + getDocumentLoader(context: IAgentContext, attemptToFetchContexts: boolean = false) { return extendContextLoader(async (url: string) => { // console.log(`resolving context for: ${url}`) @@ -55,8 +52,11 @@ export class LdCredentialModule { // currently, Veramo LD suites can modify the resolution response for DIDs from // the document Loader. This allows us to fix incompatibilities between DID Documents // and LD suites to be fixed specifically within the Veramo LD Suites definition + // TODO: every suite takes turns modifying the result, potentially leading to overwrites and incompatibilities + // between concurrent suites. Ideally, this should be performed by each suite only before it interacts with the + // document loader, to allow each suite to massage the verification methods into formats it knows about. for (const x of this.ldSuiteLoader.getAllSignatureSuites()) { - result = (await x.preDidResolutionModification(url, result, context)) || result; + result = (await x.preDidResolutionModification(url, result, context)) || result } // console.log(`Returning from Documentloader: ${JSON.stringify(returnDocument)}`) @@ -110,10 +110,11 @@ export class LdCredentialModule { options: any, context: IAgentContext, ): Promise { + // TODO: try multiple matching suites until one works or list is exhausted const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType( key.type, key.meta?.verificationMethod?.type ?? '', - ) + )[0] const documentLoader = this.getDocumentLoader(context, options.fetchRemoteContexts) // some suites can modify the incoming credential (e.g. add required contexts) @@ -138,10 +139,11 @@ export class LdCredentialModule { options: any, context: IAgentContext, ): Promise { + // TODO: try multiple matching suites until one works or list is exhausted const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType( key.type, key.meta?.verificationMethod?.type ?? '', - ) + )[0] const documentLoader = this.getDocumentLoader(context, options.fetchRemoteContexts) suite.preSigningPresModification(presentation) diff --git a/packages/credential-ld/src/ld-suite-loader.ts b/packages/credential-ld/src/ld-suite-loader.ts index ea74f8984..eaab6c712 100644 --- a/packages/credential-ld/src/ld-suite-loader.ts +++ b/packages/credential-ld/src/ld-suite-loader.ts @@ -1,23 +1,23 @@ import { VeramoLdSignature } from './ld-suites.js' import { TKeyType } from '@veramo/core-types' +import { asArray } from '@veramo/utils' /** * Initializes a list of Veramo-wrapped LD Signature suites and exposes those to the Agent Module */ export class LdSuiteLoader { constructor(options: { veramoLdSignatures: VeramoLdSignature[] }) { - options.veramoLdSignatures.forEach((obj) => { - // FIXME: some suites would work for multiple key types, but this only returns a single value per suite. - // For example, EcdsaSecp256k1RecoverySignature2020 should work with both EcdsaSecp256k1VerificationKey2019 - // as well as EcdsaSecp256k1RecoveryMethod2020 since the VerificationKey can also be expressed as the recovery - // method. - const keyType = obj.getSupportedVeramoKeyType() - const verificationType = obj.getSupportedVerificationType() - return (this.signatureMap[keyType] = { ...this.signatureMap[keyType], [verificationType]: obj }) + options.veramoLdSignatures.forEach((ldSuite) => { + const keyType = ldSuite.getSupportedVeramoKeyType() + let verifierMapping = this.signatureMap[keyType] ?? {} + asArray(ldSuite.getSupportedVerificationType()).forEach((verificationType) => { + verifierMapping[verificationType] = [...(verifierMapping[verificationType] ?? []), ldSuite] + }) + return (this.signatureMap[keyType] = { ...this.signatureMap[keyType], ...verifierMapping }) }) } - private signatureMap: Record> = {} + private signatureMap: Record> = {} getSignatureSuiteForKeyType(type: TKeyType, verificationType: string) { const suite = this.signatureMap[type]?.[verificationType] @@ -29,7 +29,7 @@ export class LdSuiteLoader { getAllSignatureSuites(): VeramoLdSignature[] { return Object.values(this.signatureMap) .map((x) => Object.values(x)) - .flat() + .flat(2) } getAllSignatureSuiteTypes() { diff --git a/packages/credential-ld/src/ld-suites.ts b/packages/credential-ld/src/ld-suites.ts index 28331f1ce..61ad61609 100644 --- a/packages/credential-ld/src/ld-suites.ts +++ b/packages/credential-ld/src/ld-suites.ts @@ -23,7 +23,7 @@ export abstract class VeramoLdSignature { // Add type definition as soon as https://github.com/digitalbazaar/jsonld-signatures // supports those. - abstract getSupportedVerificationType(): string + abstract getSupportedVerificationType(): string | string[] abstract getSupportedVeramoKeyType(): TKeyType diff --git a/packages/credential-ld/src/suites/EcdsaSecp256k1RecoverySignature2020.ts b/packages/credential-ld/src/suites/EcdsaSecp256k1RecoverySignature2020.ts index 7a8e8b764..cdac124bb 100644 --- a/packages/credential-ld/src/suites/EcdsaSecp256k1RecoverySignature2020.ts +++ b/packages/credential-ld/src/suites/EcdsaSecp256k1RecoverySignature2020.ts @@ -13,6 +13,8 @@ const { EcdsaSecp256k1RecoveryMethod2020, EcdsaSecp256k1RecoverySignature2020 } export class VeramoEcdsaSecp256k1RecoverySignature2020 extends VeramoLdSignature { getSupportedVerificationType(): string { return 'EcdsaSecp256k1RecoveryMethod2020' + // TODO: add support for ['EcdsaSecp256k1VerificationKey2020', 'EcdsaSecp256k1VerificationKey2019', + // 'JsonWebKey2020', 'Multikey'] } getSupportedVeramoKeyType(): TKeyType { @@ -52,7 +54,7 @@ export class VeramoEcdsaSecp256k1RecoverySignature2020 extends VeramoLdSignature key: new EcdsaSecp256k1RecoveryMethod2020({ publicKeyHex: key.publicKeyHex, signer: () => signer, - type: this.getSupportedVerificationType(), + type: 'EcdsaSecp256k1RecoveryMethod2020', controller, id: verifiableMethodId, }), diff --git a/packages/credential-ld/src/suites/Ed25519Signature2018.ts b/packages/credential-ld/src/suites/Ed25519Signature2018.ts index 236e4d049..17b03a515 100644 --- a/packages/credential-ld/src/suites/Ed25519Signature2018.ts +++ b/packages/credential-ld/src/suites/Ed25519Signature2018.ts @@ -9,8 +9,9 @@ import { Ed25519Signature2018, Ed25519VerificationKey2018 } from '@transmute/ed2 * @alpha This API is experimental and is very likely to change or disappear in future releases without notice. */ export class VeramoEd25519Signature2018 extends VeramoLdSignature { - getSupportedVerificationType(): string { - return 'Ed25519VerificationKey2018' + getSupportedVerificationType(): string[] { + return ['Ed25519VerificationKey2018', 'JsonWebKey2020'] + // TODO: add support for ['Ed25519VerificationKey2020', 'Multikey'] } getSupportedVeramoKeyType(): TKeyType { @@ -54,7 +55,7 @@ export class VeramoEd25519Signature2018 extends VeramoLdSignature { controller, publicKey: hexToBytes(key.publicKeyHex), signer: () => signer, - type: this.getSupportedVerificationType(), + type: 'Ed25519VerificationKey2018', }) // overwrite the signer since we're not passing the private key and transmute doesn't support that behavior verificationKey.signer = () => signer as any diff --git a/packages/credential-ld/src/suites/Ed25519Signature2020.ts b/packages/credential-ld/src/suites/Ed25519Signature2020.ts index bf63d7354..f90a273b9 100644 --- a/packages/credential-ld/src/suites/Ed25519Signature2020.ts +++ b/packages/credential-ld/src/suites/Ed25519Signature2020.ts @@ -30,8 +30,9 @@ const debug = Debug('veramo:credential-ld:Ed25519Signature2020') * @alpha This API is experimental and is very likely to change or disappear in future releases without notice. */ export class VeramoEd25519Signature2020 extends VeramoLdSignature { - getSupportedVerificationType(): string { - return 'Ed25519VerificationKey2020' + getSupportedVerificationType(): string[] { + return ['Ed25519VerificationKey2020', 'Ed25519VerificationKey2018'] + // TODO: add support for ['JsonWebKey2020', 'Multikey'] } getSupportedVeramoKeyType(): TKeyType { @@ -72,7 +73,7 @@ export class VeramoEd25519Signature2020 extends VeramoLdSignature { }) // overwrite the signer since we're not passing the private key verificationKey.signer = () => signer as any - verificationKey.type = this.getSupportedVerificationType() + verificationKey.type = 'Ed25519VerificationKey2020' return new Ed25519Signature2020({ key: verificationKey, signer: signer, diff --git a/packages/credential-ld/src/suites/JsonWebSignature2020.ts b/packages/credential-ld/src/suites/JsonWebSignature2020.ts index 9a1319a4a..adc7278af 100644 --- a/packages/credential-ld/src/suites/JsonWebSignature2020.ts +++ b/packages/credential-ld/src/suites/JsonWebSignature2020.ts @@ -17,8 +17,9 @@ import { * @alpha This API is experimental and is very likely to change or disappear in future releases without notice. */ export class VeramoJsonWebSignature2020 extends VeramoLdSignature { - getSupportedVerificationType(): 'JsonWebKey2020' { + getSupportedVerificationType(): string { return 'JsonWebKey2020' + // TODO: add support for ['Ed25519VerificationKey2018', 'Ed25519VerificationKey2020', 'Multikey'] and others } getSupportedVeramoKeyType(): TKeyType { @@ -59,7 +60,7 @@ export class VeramoJsonWebSignature2020 extends VeramoLdSignature { const verificationKey = await JsonWebKey.from({ id: id, - type: this.getSupportedVerificationType(), + type: 'JsonWebKey2020', controller: controller, publicKeyJwk: { kty: 'OKP',