From f9ad9c0781e5677103715da53601e2a299850230 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 12 Nov 2024 15:12:32 +0100 Subject: [PATCH 1/7] chore: hasher option in OpSession & toUniformPresentation for sd-jwt --- .../siopv2-oid4vp-op-auth/src/session/OpSession.ts | 7 +++++-- .../src/types/IDidAuthSiopOpAuthenticator.ts | 2 ++ packages/ssi-types/src/mapper/credential-mapper.ts | 13 +++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index 4b395a189..72de9555b 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -213,6 +213,10 @@ export class OpSession { } public async getOID4VP(args: IOpSessionGetOID4VPArgs): Promise { + if (args.hasher && !this.options.hasher) { + // capture hasher when possible and not present, can be useful for existing implementations + this.options.hasher = args.hasher + } return await OID4VP.init(this, args.allIdentifiers ?? [], args.hasher) } @@ -302,7 +306,6 @@ export class OpSession { const verification: Verification = { presentationVerificationCallback: this.createPresentationVerificationCallback(this.context), } - const request = await this.getAuthorizationRequest() const hasDefinitions = await this.hasPresentationDefinitions() if (hasDefinitions) { @@ -310,7 +313,7 @@ export class OpSession { return sum + pd.definition.input_descriptors.length }, 0) const totalVCs = args.verifiablePresentations?.reduce((sum, vp) => { - const uvp = CredentialMapper.toUniformPresentation(vp) + const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: args.hasher ?? this.options.hasher }) return sum + (uvp.verifiableCredential?.length ?? 0) }, 0) diff --git a/packages/siopv2-oid4vp-op-auth/src/types/IDidAuthSiopOpAuthenticator.ts b/packages/siopv2-oid4vp-op-auth/src/types/IDidAuthSiopOpAuthenticator.ts index 68497ff1a..047c9d20d 100644 --- a/packages/siopv2-oid4vp-op-auth/src/types/IDidAuthSiopOpAuthenticator.ts +++ b/packages/siopv2-oid4vp-op-auth/src/types/IDidAuthSiopOpAuthenticator.ts @@ -122,6 +122,7 @@ export interface IOpsSendSiopAuthorizationResponseArgs { // verifiedAuthorizationRequest: VerifiedAuthorizationRequest presentationSubmission?: PresentationSubmission verifiablePresentations?: W3CVerifiablePresentation[] + hasher?: Hasher } export enum events { @@ -158,6 +159,7 @@ export interface IOPOptions { presentationSignCallback?: PresentationSignCallback resolveOpts?: ResolveOpts + hasher?: Hasher } /* diff --git a/packages/ssi-types/src/mapper/credential-mapper.ts b/packages/ssi-types/src/mapper/credential-mapper.ts index a1da2a0e0..67ab3bb60 100644 --- a/packages/ssi-types/src/mapper/credential-mapper.ts +++ b/packages/ssi-types/src/mapper/credential-mapper.ts @@ -162,12 +162,13 @@ export class CredentialMapper { deviceResponse = originalPresentation } - const mdocCredentials = deviceResponse.documents - ?.map((doc) => CredentialMapper.toWrappedVerifiableCredential(doc, opts) as WrappedMdocCredential) - if (!mdocCredentials || mdocCredentials.length === 0 ) { + const mdocCredentials = deviceResponse.documents?.map( + (doc) => CredentialMapper.toWrappedVerifiableCredential(doc, opts) as WrappedMdocCredential + ) + if (!mdocCredentials || mdocCredentials.length === 0) { throw new Error('could not extract any mdoc credentials from mdoc device response') } - + return { type: CredentialMapper.isMsoMdocDecodedPresentation(originalPresentation) ? OriginalType.MSO_MDOC_DECODED : OriginalType.MSO_MDOC_ENCODED, format: 'mso_mdoc', @@ -616,7 +617,7 @@ export class CredentialMapper { static toUniformPresentation( presentation: OriginalVerifiablePresentation, - opts?: { maxTimeSkewInMS?: number; addContextIfMissing?: boolean } + opts?: { maxTimeSkewInMS?: number; addContextIfMissing?: boolean; hasher?: Hasher } ): IVerifiablePresentation { if (CredentialMapper.isSdJwtDecodedCredential(presentation)) { throw new Error('Converting SD-JWT VC to uniform VP is not supported.') @@ -631,7 +632,7 @@ export class CredentialMapper { 'Could not determine original presentation, probably it was a converted JWT presentation, that is now missing the JWT value in the proof' ) } - const decoded = CredentialMapper.decodeVerifiablePresentation(original) + const decoded = CredentialMapper.decodeVerifiablePresentation(original, opts?.hasher) const isJwtEncoded: boolean = CredentialMapper.isJwtEncoded(original) const isJwtDecoded: boolean = CredentialMapper.isJwtDecodedPresentation(original) const uniformPresentation = From 64fac6fb1d024c5a78ec99e9c96c49942e53568c Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 12 Nov 2024 15:53:09 +0100 Subject: [PATCH 2/7] chore: hasher option in OpSession & toUniformPresentation for sd-jwt --- .../src/session/OpSession.ts | 2 +- pnpm-lock.yaml | 31 ------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index 72de9555b..1e6dce496 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -314,7 +314,7 @@ export class OpSession { }, 0) const totalVCs = args.verifiablePresentations?.reduce((sum, vp) => { const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: args.hasher ?? this.options.hasher }) - return sum + (uvp.verifiableCredential?.length ?? 0) + return sum + ((uvp.verifiableCredential?.length ?? CredentialMapper.isSdJwtDecodedCredential(uvp)) ? 1 : 0) }, 0) if (!request.presentationDefinitions || !args.verifiablePresentations || totalVCs !== totalInputDescriptors) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 433206beb..d424a27ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1559,37 +1559,6 @@ importers: specifier: ^13.5.5 version: 13.5.5 - packages/oidf-metatdata-server: - dependencies: - '@sphereon/ssi-express-support': - specifier: workspace:* - version: link:../ssi-express-support - '@sphereon/ssi-sdk.oid4vci-issuer-store': - specifier: workspace:* - version: link:../oid4vci-issuer-store - debug: - specifier: ^4.3.5 - version: 4.3.6 - express: - specifier: ^4.19.2 - version: 4.21.1 - semver: - specifier: ^7.6.3 - version: 7.6.3 - devDependencies: - '@sphereon/ssi-sdk.agent-config': - specifier: workspace:* - version: link:../agent-config - '@types/express': - specifier: ^4.17.21 - version: 4.17.21 - '@types/express-serve-static-core': - specifier: ^4.19.5 - version: 4.19.5 - '@types/semver': - specifier: ^7.5.8 - version: 7.5.8 - packages/pd-manager: dependencies: '@sphereon/pex': From 5fae14c25d7cb850e2759b0ff2d0d650c10b4df2 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Tue, 12 Nov 2024 16:19:21 +0100 Subject: [PATCH 3/7] chore: hasher option in OpSession & toUniformPresentation for sd-jwt --- packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index 1e6dce496..c40ecdd49 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -213,10 +213,6 @@ export class OpSession { } public async getOID4VP(args: IOpSessionGetOID4VPArgs): Promise { - if (args.hasher && !this.options.hasher) { - // capture hasher when possible and not present, can be useful for existing implementations - this.options.hasher = args.hasher - } return await OID4VP.init(this, args.allIdentifiers ?? [], args.hasher) } From 339900d89cc96f1c3ed89635b31de3a89c542910 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Thu, 14 Nov 2024 15:29:10 +0100 Subject: [PATCH 4/7] chore: upgraded countVCsInAllVPs --- .../src/session/OpSession.ts | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index c40ecdd49..4517b4162 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -16,13 +16,21 @@ import { ResolveOpts } from '@sphereon/did-auth-siop-adapter' import { JwtIssuer } from '@sphereon/oid4vc-common' import { getAgentDIDMethods, getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils' import { encodeBase64url } from '@sphereon/ssi-sdk.core' -import { CompactSdJwtVc, CredentialMapper, parseDid, PresentationSubmission, W3CVerifiablePresentation } from '@sphereon/ssi-types' +import { + CompactSdJwtVc, + CredentialMapper, + OriginalVerifiableCredential, + parseDid, + PresentationSubmission, + W3CVerifiablePresentation, +} from '@sphereon/ssi-types' import { IIdentifier, IVerifyResult, TKeyType } from '@veramo/core' import Debug from 'debug' import { v4 } from 'uuid' import { IOPOptions, IOpSessionArgs, IOpSessionGetOID4VPArgs, IOpsSendSiopAuthorizationResponseArgs, IRequiredContext } from '../types' import { createOP } from './functions' import { OID4VP } from './OID4VP' +import { PEX } from '@sphereon/pex' const debug = Debug(`sphereon:sdk:siop:op-session`) @@ -308,10 +316,7 @@ export class OpSession { const totalInputDescriptors = request.presentationDefinitions?.reduce((sum, pd) => { return sum + pd.definition.input_descriptors.length }, 0) - const totalVCs = args.verifiablePresentations?.reduce((sum, vp) => { - const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: args.hasher ?? this.options.hasher }) - return sum + ((uvp.verifiableCredential?.length ?? CredentialMapper.isSdJwtDecodedCredential(uvp)) ? 1 : 0) - }, 0) + const totalVCs = this.countVCsInAllVPs(args) if (!request.presentationDefinitions || !args.verifiablePresentations || totalVCs !== totalInputDescriptors) { throw Error( @@ -360,6 +365,19 @@ export class OpSession { return response } } + + private countVCsInAllVPs(args: IOpsSendSiopAuthorizationResponseArgs) { + return args.verifiablePresentations?.reduce((sum, vp) => { + const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: args.hasher ?? this.options.hasher }) + if (uvp.verifiableCredential?.length) { + return sum + uvp.verifiableCredential?.length + } + if (!PEX.allowMultipleVCsPerPresentation(uvp.verifiableCredential as Array)) { + return sum + 1 + } + return 0 + }, 0) + } } function convertDidMethod(didMethod: string, didPrefix?: boolean): string { From ac9c9accaa12e496cccbdbef0e85eb708e50653f Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Thu, 14 Nov 2024 15:33:22 +0100 Subject: [PATCH 5/7] chore: upgraded countVCsInAllVPs --- packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index 4517b4162..361d2e2cb 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -19,6 +19,7 @@ import { encodeBase64url } from '@sphereon/ssi-sdk.core' import { CompactSdJwtVc, CredentialMapper, + Hasher, OriginalVerifiableCredential, parseDid, PresentationSubmission, @@ -316,7 +317,7 @@ export class OpSession { const totalInputDescriptors = request.presentationDefinitions?.reduce((sum, pd) => { return sum + pd.definition.input_descriptors.length }, 0) - const totalVCs = this.countVCsInAllVPs(args) + const totalVCs = this.countVCsInAllVPs(args.verifiablePresentations, args.hasher) if (!request.presentationDefinitions || !args.verifiablePresentations || totalVCs !== totalInputDescriptors) { throw Error( @@ -366,9 +367,9 @@ export class OpSession { } } - private countVCsInAllVPs(args: IOpsSendSiopAuthorizationResponseArgs) { - return args.verifiablePresentations?.reduce((sum, vp) => { - const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: args.hasher ?? this.options.hasher }) + private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[] | undefined, hasher: Hasher | undefined) { + return verifiablePresentations?.reduce((sum, vp) => { + const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: hasher ?? this.options.hasher }) if (uvp.verifiableCredential?.length) { return sum + uvp.verifiableCredential?.length } From dfda46ac0ff3e2d07c894f64792f618a87cad4c2 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Thu, 14 Nov 2024 15:41:09 +0100 Subject: [PATCH 6/7] chore: upgraded countVCsInAllVPs --- packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index 361d2e2cb..a47f25264 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -376,7 +376,7 @@ export class OpSession { if (!PEX.allowMultipleVCsPerPresentation(uvp.verifiableCredential as Array)) { return sum + 1 } - return 0 + return sum }, 0) } } From 142778adff98d537835f759d5db5a3607a9a1c08 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Thu, 14 Nov 2024 16:13:49 +0100 Subject: [PATCH 7/7] chore: upgraded countVCsInAllVPs --- packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts index a47f25264..6fcb860f2 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OpSession.ts @@ -317,7 +317,7 @@ export class OpSession { const totalInputDescriptors = request.presentationDefinitions?.reduce((sum, pd) => { return sum + pd.definition.input_descriptors.length }, 0) - const totalVCs = this.countVCsInAllVPs(args.verifiablePresentations, args.hasher) + const totalVCs = args.verifiablePresentations ? this.countVCsInAllVPs(args.verifiablePresentations, args.hasher) : 0 if (!request.presentationDefinitions || !args.verifiablePresentations || totalVCs !== totalInputDescriptors) { throw Error( @@ -367,8 +367,8 @@ export class OpSession { } } - private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[] | undefined, hasher: Hasher | undefined) { - return verifiablePresentations?.reduce((sum, vp) => { + private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[], hasher?: Hasher) { + return verifiablePresentations.reduce((sum, vp) => { const uvp = CredentialMapper.toUniformPresentation(vp, { hasher: hasher ?? this.options.hasher }) if (uvp.verifiableCredential?.length) { return sum + uvp.verifiableCredential?.length