From 90fd94d62fb989eefc864a3ecb36221c7921d251 Mon Sep 17 00:00:00 2001 From: Berend Sliedrecht Date: Thu, 2 Nov 2023 10:50:04 +0100 Subject: [PATCH] fix(sd-jwt): resolved most of the feedback Signed-off-by: Berend Sliedrecht --- packages/sd-jwt/README.md | 12 ++------ packages/sd-jwt/package.json | 4 +-- packages/sd-jwt/src/SdJwtApi.ts | 7 ++--- packages/sd-jwt/src/SdJwtOptions.ts | 4 +-- packages/sd-jwt/src/SdJwtService.ts | 46 +++++++++++++---------------- 5 files changed, 29 insertions(+), 44 deletions(-) diff --git a/packages/sd-jwt/README.md b/packages/sd-jwt/README.md index f096508b85..8ba2c79779 100644 --- a/packages/sd-jwt/README.md +++ b/packages/sd-jwt/README.md @@ -30,13 +30,7 @@ ### Installation -Make sure you have set up the correct version of Aries Framework JavaScript according to the AFJ repository. To find out which version of AFJ you need to have installed you can run the following command. This will list the required peer dependency for `@aries-framework/core`. - -```sh -npm info "@aries-framework/sd-jwt" peerDependencies -``` - -Then add the sd-jwt module to your project. +Add the `sd-jwt` module to your project. ```sh yarn add @aries-framework/sd-jwt @@ -44,9 +38,7 @@ yarn add @aries-framework/sd-jwt ### Quick start -In order for this module to work, we have to inject it into the agent to access agent functionality. See the example for more information. - -### Example of usage +After the installation you can follow the [guide to setup your agent](https://aries.js.org/guides/0.4/getting-started/set-up) and add the following to your agent modules. ```ts import { SdJwtModule } from '@aries-framework/sd-jwt' diff --git a/packages/sd-jwt/package.json b/packages/sd-jwt/package.json index bdcd3605a8..1528080e9e 100644 --- a/packages/sd-jwt/package.json +++ b/packages/sd-jwt/package.json @@ -2,7 +2,7 @@ "name": "@aries-framework/sd-jwt", "main": "build/index", "types": "build/index", - "version": "0.4.1", + "version": "0.4.2", "files": [ "build" ], @@ -28,7 +28,7 @@ "@aries-framework/core": "^0.4.2", "class-transformer": "0.5.1", "class-validator": "0.14.0", - "jwt-sd": "^0.0.1-alpha.20" + "jwt-sd": "^0.1.0" }, "devDependencies": { "@hyperledger/aries-askar-nodejs": "^0.1.0", diff --git a/packages/sd-jwt/src/SdJwtApi.ts b/packages/sd-jwt/src/SdJwtApi.ts index ebec05da74..9073994061 100644 --- a/packages/sd-jwt/src/SdJwtApi.ts +++ b/packages/sd-jwt/src/SdJwtApi.ts @@ -66,11 +66,8 @@ export class SdJwtApi { return await this.sdJwtService.verify(this.agentContext, sdJwtCompact, options) } - public async getCredentialRecordByIdM< - Header extends Record = Record, - Payload extends Record = Record - >(id: string): Promise> { - return await this.sdJwtService.getCredentialRecordById(this.agentContext, id) + public async getCredentialRecordById(id: string): Promise { + return await this.sdJwtService.getCredentialRecordById(this.agentContext, id) } public async getAllCredentialRecords(): Promise> { diff --git a/packages/sd-jwt/src/SdJwtOptions.ts b/packages/sd-jwt/src/SdJwtOptions.ts index 60eda8ff59..190ad005e4 100644 --- a/packages/sd-jwt/src/SdJwtOptions.ts +++ b/packages/sd-jwt/src/SdJwtOptions.ts @@ -4,7 +4,7 @@ import type { DisclosureFrame } from 'jwt-sd' export type SdJwtCreateOptions = Record> = { holderDidUrl: string issuerDidUrl: string - issuerOverrideJsonWebAlgorithm?: JwaSignatureAlgorithm + jsonWebAlgorithm?: JwaSignatureAlgorithm disclosureFrame?: DisclosureFrame hashingAlgorithm?: HashName } @@ -18,7 +18,7 @@ export type SdJwtReceiveOptions = { * `includedDisclosureIndices` is not the best API, but it is the best alternative until something like `PEX` is supported */ export type SdJwtPresentOptions = { - holderOverrideJsonWebAlgorithm?: JwaSignatureAlgorithm + jsonWebAlgorithm?: JwaSignatureAlgorithm includedDisclosureIndices?: Array /** diff --git a/packages/sd-jwt/src/SdJwtService.ts b/packages/sd-jwt/src/SdJwtService.ts index 52925ac8ab..1cbc2ab876 100644 --- a/packages/sd-jwt/src/SdJwtService.ts +++ b/packages/sd-jwt/src/SdJwtService.ts @@ -3,8 +3,8 @@ import type { AgentContext, JwkJson, Query } from '@aries-framework/core' import type { Signer, SdJwtVcVerificationResult, Verifier, HasherAndAlgorithm } from 'jwt-sd' import { + parseDid, DidResolverService, - getJwaFromKey, getKeyFromVerificationMethod, getJwkFromJson, Key, @@ -49,8 +49,7 @@ export class SdJwtService { algorithm: HasherAlgorithm.Sha256, hasher: (input: string) => { const serializedInput = TypedArrayEncoder.fromString(input) - const hash = Hasher.hash(serializedInput, 'sha2-256') - return TypedArrayEncoder.toBase64URL(hash) + return Hasher.hash(serializedInput, 'sha2-256') }, } } @@ -102,15 +101,15 @@ export class SdJwtService { holderDidUrl, disclosureFrame, hashingAlgorithm = 'sha2-256', - issuerOverrideJsonWebAlgorithm, + jsonWebAlgorithm, }: SdJwtCreateOptions ): Promise<{ sdJwtRecord: SdJwtRecord; compact: string }> { if (hashingAlgorithm !== 'sha2-256') { throw new SdJwtError(`Unsupported hashing algorithm used: ${hashingAlgorithm}`) } - const issuerKeyId = issuerDidUrl.split('#')[1] - if (!issuerKeyId) { + const parsedDid = parseDid(issuerDidUrl) + if (!parsedDid.fragment) { throw new SdJwtError( `issuer did url '${issuerDidUrl}' does not contain a '#'. Unable to derive key from did document` ) @@ -121,7 +120,7 @@ export class SdJwtService { issuerDidUrl ) const issuerKey = getKeyFromVerificationMethod(issuerVerificationMethod) - const alg = getJwaFromKey(issuerKey, issuerOverrideJsonWebAlgorithm) + const alg = jsonWebAlgorithm ?? getJwkFromKey(issuerKey).supportedSignatureAlgorithms[0] const { verificationMethod: holderVerificationMethod } = await this.resolveDidUrl(agentContext, holderDidUrl) const holderKey = getKeyFromVerificationMethod(holderVerificationMethod) @@ -130,7 +129,7 @@ export class SdJwtService { const header = { alg: alg.toString(), typ: 'vc+sd-jwt', - kid: issuerKeyId, + kid: parsedDid.fragment, } const sdJwtVc = new SdJwtVc({}, { disclosureFrame }) @@ -175,22 +174,22 @@ export class SdJwtService { public async receive< Header extends Record = Record, - Payload extends Record = Record + Payload extends Record = Record, >( agentContext: AgentContext, sdJwtCompact: string, { issuerDidUrl, holderDidUrl }: SdJwtReceiveOptions ): Promise { - const sdJwt = SdJwtVc.fromCompact(sdJwtCompact) + const sdJwtVc = SdJwtVc.fromCompact(sdJwtCompact) - if (!sdJwt.signature) { + if (!sdJwtVc.signature) { throw new SdJwtError('A signature must be included for an sd-jwt') } const { verificationMethod: issuerVerificationMethod } = await this.resolveDidUrl(agentContext, issuerDidUrl) const issuerKey = getKeyFromVerificationMethod(issuerVerificationMethod) - const isSignatureValid = await sdJwt.verifySignature(this.verifier(agentContext, issuerKey)) + const { isSignatureValid } = await sdJwtVc.verify(this.verifier(agentContext, issuerKey)) if (!isSignatureValid) { throw new SdJwtError('sd-jwt has an invalid signature from the issuer') @@ -200,14 +199,14 @@ export class SdJwtService { const holderKey = getKeyFromVerificationMethod(holderVerificiationMethod) const holderKeyJwk = getJwkFromKey(holderKey).toJson() - sdJwt.assertClaimInPayload('cnf', { jwk: holderKeyJwk }) + sdJwtVc.assertClaimInPayload('cnf', { jwk: holderKeyJwk }) const sdJwtRecord = new SdJwtRecord({ sdJwt: { - header: sdJwt.header, - payload: sdJwt.payload, - signature: sdJwt.signature, - disclosures: sdJwt.disclosures?.map((d) => d.decoded), + header: sdJwtVc.header, + payload: sdJwtVc.payload, + signature: sdJwtVc.signature, + disclosures: sdJwtVc.disclosures?.map((d) => d.decoded), holderDidUrl, }, }) @@ -220,14 +219,14 @@ export class SdJwtService { public async present( agentContext: AgentContext, sdJwtRecord: SdJwtRecord, - { includedDisclosureIndices, verifierMetadata, holderOverrideJsonWebAlgorithm }: SdJwtPresentOptions + { includedDisclosureIndices, verifierMetadata, jsonWebAlgorithm }: SdJwtPresentOptions ): Promise { const { verificationMethod: holderVerificationMethod } = await this.resolveDidUrl( agentContext, sdJwtRecord.sdJwt.holderDidUrl ) const holderKey = getKeyFromVerificationMethod(holderVerificationMethod) - const alg = getJwaFromKey(holderKey, holderOverrideJsonWebAlgorithm) + const alg = jsonWebAlgorithm ?? getJwkFromKey(holderKey).supportedSignatureAlgorithms[0] const header = { alg: alg.toString(), @@ -256,7 +255,7 @@ export class SdJwtService { public async verify< Header extends Record = Record, - Payload extends Record = Record + Payload extends Record = Record, >( agentContext: AgentContext, sdJwtCompact: string, @@ -312,11 +311,8 @@ export class SdJwtService { } } - public async getCredentialRecordById< - Header extends Record = Record, - Payload extends Record = Record - >(agentContext: AgentContext, id: string): Promise> { - return (await this.sdJwtRepository.getById(agentContext, id)) as SdJwtRecord + public async getCredentialRecordById(agentContext: AgentContext, id: string): Promise { + return (await this.sdJwtRepository.getById(agentContext, id)) as SdJwtRecord } public async getAllCredentialRecords(agentContext: AgentContext): Promise> {