From 43a3adfbe683ee4040a293cc5b75d17a029d7c49 Mon Sep 17 00:00:00 2001 From: nklomp Date: Mon, 9 Jan 2023 16:13:23 +0100 Subject: [PATCH] feat: Jsonweb2020 sig support --- .../shared/connectionManagerAgentLogic.ts | 4 +- packages/vc-handler-ld-local/src/index.ts | 1 + .../src/suites/JsonWebSignature2020.ts | 110 ++++++++++++++++++ .../vc-handler-ld-local/src/suites/index.ts | 1 + 4 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 packages/vc-handler-ld-local/src/suites/JsonWebSignature2020.ts diff --git a/packages/connection-manager/__tests__/shared/connectionManagerAgentLogic.ts b/packages/connection-manager/__tests__/shared/connectionManagerAgentLogic.ts index 28fc6cf15..835b1cb13 100644 --- a/packages/connection-manager/__tests__/shared/connectionManagerAgentLogic.ts +++ b/packages/connection-manager/__tests__/shared/connectionManagerAgentLogic.ts @@ -125,7 +125,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro const party = { name, alias, - uri: 'example.com' + uri: 'example.com', } await expect(agent.cmAddParty(party)).rejects.toThrow('Blank aliases are not allowed') @@ -137,7 +137,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro const party = { name, alias, - uri: 'example.com' + uri: 'example.com', } await expect(agent.cmAddParty(party)).rejects.toThrow('Blank names are not allowed') diff --git a/packages/vc-handler-ld-local/src/index.ts b/packages/vc-handler-ld-local/src/index.ts index dc8b89fc6..aa4a6bfa3 100644 --- a/packages/vc-handler-ld-local/src/index.ts +++ b/packages/vc-handler-ld-local/src/index.ts @@ -8,6 +8,7 @@ export { SphereonEd25519Signature2018, SphereonEd25519Signature2020, SphereonEcdsaSecp256k1RecoverySignature2020, + SphereonJsonWebSignature2020 } from './suites' export * from './ld-credential-module' export * from './ld-context-loader' diff --git a/packages/vc-handler-ld-local/src/suites/JsonWebSignature2020.ts b/packages/vc-handler-ld-local/src/suites/JsonWebSignature2020.ts new file mode 100644 index 000000000..9d568cb71 --- /dev/null +++ b/packages/vc-handler-ld-local/src/suites/JsonWebSignature2020.ts @@ -0,0 +1,110 @@ +import { CredentialPayload, DIDDocument, IAgentContext, IKey, TKeyType, VerifiableCredential } from '@veramo/core' +import { RequiredAgentMethods, SphereonLdSignature } from '../ld-suites' +import * as u8a from 'uint8arrays' +import { JsonWebKey, JsonWebSignature } from '@transmute/json-web-signature' +import { asArray, encodeJoseBlob } from '@veramo/utils' + +/** + * Veramo wrapper for the JsonWebSignature2020 suite by Transmute Industries + * + * @alpha This API is experimental and is very likely to change or disappear in future releases without notice. + */ +export class SphereonJsonWebSignature2020 extends SphereonLdSignature { + getSupportedVerificationType(): 'JsonWebKey2020' { + return 'JsonWebKey2020' + } + + getSupportedVeramoKeyType(): TKeyType { + // @ts-ignore + return 'RSA' + } + + async getSuiteForSigning(key: IKey, issuerDid: string, verificationMethodId: string, context: IAgentContext): Promise { + const controller = issuerDid + + // DID Key ID + let id = verificationMethodId + + let alg = 'RS256' + if (key.type === 'Ed25519' || key.type === 'X25519') { + alg = 'EdDSA' + } else if (key.type === 'Secp256k1') { + alg = 'ES256k' + throw Error('ES256k keys not supported yet (to JWK missing)') + } else if (key.type === 'Secp256r1') { + alg = 'ES256' + throw Error('ES256 keys not supported yet (to JWK missing)') + } else if (key.type === 'Bls12381G1') { + throw Error('BLS keys as jsonwebkey2020 not implemented yet') + } + + const signer = { + // returns a JWS detached + sign: async (args: { data: Uint8Array }): Promise => { + const header = { + alg, + b64: false, + crit: ['b64'], + } + const headerString = encodeJoseBlob(header) + const messageBuffer = u8a.concat([u8a.fromString(`${headerString}.`, 'utf-8'), args.data]) + const messageString = u8a.toString(messageBuffer, 'base64') + const signature = await context.agent.keyManagerSign({ + keyRef: key.kid, + algorithm: alg, + data: messageString, + encoding: 'base64', + }) + return `${headerString}..${signature}` + }, + } + + const publicKeyJwk = key.meta?.publicKeyJwk + ? key.meta.publicKeyJwk + : { + kty: 'OKP', + crv: 'Ed25519', + x: u8a.toString(u8a.fromString(key.publicKeyHex, 'hex'), 'base64url'), + } + + const verificationKey = await JsonWebKey.from({ + id: id, + type: this.getSupportedVerificationType(), + controller: controller, + publicKeyJwk, + }) + + verificationKey.signer = () => signer + + const suite = new JsonWebSignature({ + key: verificationKey, + }) + + return suite + } + + getSuiteForVerification(): any { + return new JsonWebSignature() + } + + preSigningCredModification(credential: CredentialPayload): void { + credential['@context'] = [...(credential['@context'] || []), this.getContext()] + } + + preDidResolutionModification(didUrl: string, didDoc: DIDDocument): void { + // do nothing + } + + getContext(): string { + return 'https://w3id.org/security/suites/jws-2020/v1' + } + + preVerificationCredModification(credential: VerifiableCredential): void { + const vcJson = JSON.stringify(credential) + if (vcJson.indexOf('JsonWebKey2020') > -1) { + if (vcJson.indexOf(this.getContext()) === -1) { + credential['@context'] = [...asArray(credential['@context'] || []), this.getContext()] + } + } + } +} diff --git a/packages/vc-handler-ld-local/src/suites/index.ts b/packages/vc-handler-ld-local/src/suites/index.ts index da61fd80c..1e413b15a 100644 --- a/packages/vc-handler-ld-local/src/suites/index.ts +++ b/packages/vc-handler-ld-local/src/suites/index.ts @@ -2,3 +2,4 @@ export { SphereonBbsBlsSignature2020 } from './BbsBlsSignature2020' export { SphereonEd25519Signature2018 } from './Ed25519Signature2018' export { SphereonEd25519Signature2020 } from './Ed25519Signature2020' export { SphereonEcdsaSecp256k1RecoverySignature2020 } from './EcdsaSecp256k1RecoverySignature2020' +export { SphereonJsonWebSignature2020 } from './JsonWebSignature2020'