From 44dabf46d5ea45db0ba3dc4d8e55343980011464 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Fri, 27 Sep 2024 12:53:40 +0200 Subject: [PATCH] fix: fixes issuer signed flow --- .../src/agent/PresentationExchange.ts | 10 +++++-- .../presentation-exchange/src/functions.ts | 12 ++++---- packages/sd-jwt/src/action-handler.ts | 11 ++++--- .../src/session/OID4VP.ts | 30 ++++++++++++------- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/packages/presentation-exchange/src/agent/PresentationExchange.ts b/packages/presentation-exchange/src/agent/PresentationExchange.ts index 9ecfb655a..cb3810d71 100644 --- a/packages/presentation-exchange/src/agent/PresentationExchange.ts +++ b/packages/presentation-exchange/src/agent/PresentationExchange.ts @@ -12,7 +12,13 @@ import { IAgentPlugin } from '@veramo/core' import { IPresentationExchange } from '../types/IPresentationExchange' import { Checked, IPresentationDefinition, PEX } from '@sphereon/pex' -import { CompactJWT, CredentialMapper, JWT_PROOF_TYPE_2020, W3CVerifiableCredential } from '@sphereon/ssi-types' +import { + CompactJWT, + CredentialMapper, + IProof, + JWT_PROOF_TYPE_2020, + W3CVerifiableCredential +} from '@sphereon/ssi-types' import { InputDescriptorV1, InputDescriptorV2 } from '@sphereon/pex-models' import { toDIDs } from '@sphereon/ssi-sdk-ext.did-utils' import { CredentialRole, UniqueDigitalCredential, verifiableCredentialForRoleFilter } from '@sphereon/ssi-sdk.credential-store' @@ -135,7 +141,7 @@ export class PresentationExchange implements IAgentPlugin { return uniqueCredentials.map((uniqueVC: UniqueDigitalCredential) => { const vc = uniqueVC.uniformVerifiableCredential! const proof = Array.isArray(vc.proof) ? vc.proof : [vc.proof] - const jwtProof = proof.find((p) => p?.type === JWT_PROOF_TYPE_2020) + const jwtProof = proof.find((p: IProof) => p?.type === JWT_PROOF_TYPE_2020) return jwtProof ? (jwtProof.jwt as CompactJWT) : vc }) } diff --git a/packages/presentation-exchange/src/functions.ts b/packages/presentation-exchange/src/functions.ts index 3ad979fdc..873cf220f 100644 --- a/packages/presentation-exchange/src/functions.ts +++ b/packages/presentation-exchange/src/functions.ts @@ -27,10 +27,7 @@ export async function createPEXPresentationSignCallback( }, context: IRequiredContext, ): Promise { - function determineProofFormat(innerArgs: { - format?: Format | 'jwt' | 'lds' | 'EthereumEip712Signature2021' - presentationDefinition: IPresentationDefinition - }): string { + function determineProofFormat(innerArgs: {format?: Format | 'jwt' | 'lds' | 'EthereumEip712Signature2021', presentationDefinition: IPresentationDefinition}): string { const { format, presentationDefinition } = innerArgs const formatOptions = format ?? presentationDefinition.format ?? args.format @@ -85,27 +82,28 @@ export async function createPEXPresentationSignCallback( idOpts.offlineWhenNoDIDRegistered = true } - const resolution = await context.agent.identifierManagedGet(idOpts) - if ('compactSdJwtVc' in presentation) { if (proofFormat !== 'vc+sd-jwt') { return Promise.reject(Error(`presentation payload does not match proof format ${proofFormat}`)) } const presentationResult = await context.agent.createSdJwtPresentation({ + ...(idOpts?.method === 'oid4vci-issuer' && { holder: idOpts?.issuer as string }), presentation: presentation.compactSdJwtVc, kb: { payload: { ...presentation.kbJwt?.payload, iat: presentation.kbJwt?.payload?.iat ?? Math.floor(Date.now() / 1000 - CLOCK_SKEW), nonce: challenge ?? presentation.kbJwt?.payload?.nonce, - aud: presentation.kbJwt?.payload?.aud ?? resolution.issuer, + aud: presentation.kbJwt?.payload?.aud ?? domain ?? args.domain }, }, }) return CredentialMapper.storedPresentationToOriginalFormat(presentationResult.presentation as OriginalVerifiablePresentation) } else { + const resolution = await context.agent.identifierManagedGet(idOpts) + if (proofFormat === 'vc+sd-jwt') { return Promise.reject(Error(`presentation payload does not match proof format ${proofFormat}`)) } diff --git a/packages/sd-jwt/src/action-handler.ts b/packages/sd-jwt/src/action-handler.ts index ca0844477..9c4161bf3 100644 --- a/packages/sd-jwt/src/action-handler.ts +++ b/packages/sd-jwt/src/action-handler.ts @@ -86,10 +86,9 @@ export class SDJwtPlugin implements IAgentPlugin { const { key, alg } = signingKey const signer: Signer = async (data: string): Promise => { - console.log('AHAAAAAAA') - return context.agent.keyManagerSign({ keyRef: key.kmsKeyRef, data }) } + return { signer, alg, signingKey } } @@ -194,9 +193,9 @@ export class SDJwtPlugin implements IAgentPlugin { kbSigner: signer, kbSignAlg: alg ?? 'ES256', }) - const credential = await sdjwt.present(args.presentation, args.presentationFrame as PresentationFrame, { kb: args.kb }) + const presentation = await sdjwt.present(args.presentation, args.presentationFrame as PresentationFrame, { kb: args.kb }) - return { presentation: credential } + return { presentation } } /** @@ -240,7 +239,7 @@ export class SDJwtPlugin implements IAgentPlugin { * @param signature - The signature * @returns */ - async verify(sdjwt: SDJwtVcInstance, context: IRequiredContext, data: string, signature: string) { + async verify(sdjwt: SDJwtVcInstance, context: IRequiredContext, data: string, signature: string): Promise { const decodedVC = await sdjwt.decode(`${data}.${signature}`) const issuer: string = ((decodedVC.jwt as Jwt).payload as Record).iss as string const header = (decodedVC.jwt as Jwt).header as Record @@ -257,7 +256,7 @@ export class SDJwtPlugin implements IAgentPlugin { }) if (certificateValidationResult.error || !certificateValidationResult?.certificateChain) { - throw new Error('Certificate chain validation failed') + return Promise.reject(Error(`Certificate chain validation failed. ${certificateValidationResult.message}`)) } const certInfo = certificateValidationResult.certificateChain[0] jwk = certInfo.publicKeyJWK as JWK diff --git a/packages/siopv2-oid4vp-op-auth/src/session/OID4VP.ts b/packages/siopv2-oid4vp-op-auth/src/session/OID4VP.ts index 57fa3e9fd..fb39d86e6 100644 --- a/packages/siopv2-oid4vp-op-auth/src/session/OID4VP.ts +++ b/packages/siopv2-oid4vp-op-auth/src/session/OID4VP.ts @@ -1,11 +1,15 @@ import { PresentationDefinitionWithLocation, PresentationExchange } from '@sphereon/did-auth-siop' import { SelectResults, Status, SubmissionRequirementMatch } from '@sphereon/pex' import { Format } from '@sphereon/pex-models' -import { ManagedIdentifierOptsOrResult, ManagedIdentifierResult } from '@sphereon/ssi-sdk-ext.identifier-resolution' +import { + isOID4VCIssuerIdentifier, + ManagedIdentifierOptsOrResult, + ManagedIdentifierResult +} from '@sphereon/ssi-sdk-ext.identifier-resolution' import { ProofOptions } from '@sphereon/ssi-sdk.core' import { UniqueDigitalCredential, verifiableCredentialForRoleFilter } from '@sphereon/ssi-sdk.credential-store' import { CredentialRole, FindDigitalCredentialArgs } from '@sphereon/ssi-sdk.data-store' -import { CompactJWT, Hasher, OriginalVerifiableCredential } from '@sphereon/ssi-types' +import { CompactJWT, Hasher, IProof, OriginalVerifiableCredential } from '@sphereon/ssi-types' import { DEFAULT_JWT_PROOF_TYPE, IGetPresentationExchangeArgs, @@ -117,10 +121,15 @@ export class OID4VP { if (typeof firstUniqueDC !== 'object' || !('digitalCredential' in firstUniqueDC)) { return Promise.reject(Error('If no opts provided, credentials should be of type UniqueDigitalCredential')) } - idOpts = await this.session.context.agent.identifierManagedGetByKid({ - identifier: firstUniqueDC.digitalCredential.kmsKeyRef, - kmsKeyRef: firstUniqueDC.digitalCredential.kmsKeyRef, - }) + + idOpts = isOID4VCIssuerIdentifier(firstUniqueDC.digitalCredential.kmsKeyRef) + ? await this.session.context.agent.identifierManagedGetByIssuer({ + identifier: firstUniqueDC.digitalCredential.kmsKeyRef, + }) + : await this.session.context.agent.identifierManagedGetByKid({ + identifier: firstUniqueDC.digitalCredential.kmsKeyRef, + kmsKeyRef: firstUniqueDC.digitalCredential.kmsKeyRef, + }) /* const holder = CredentialMapper.isSdJwtDecodedCredential(firstVC) @@ -160,6 +169,7 @@ export class OID4VP { if (!idOpts) { return Promise.reject(Error(`No identifier options present at this point`)) } + const signCallback = await createOID4VPPresentationSignCallback({ presentationSignCallback: this.session.options.presentationSignCallback, idOpts, @@ -169,7 +179,7 @@ export class OID4VP { format: opts?.restrictToFormats ?? selectedVerifiableCredentials.definition.definition.format, skipDidResolution: opts?.skipDidResolution ?? false, }) - const identifier: ManagedIdentifierResult = await this.session.context.agent.identifierManagedGet(idOpts) + const verifiableCredentials = vcs.credentials.map((credential) => typeof credential === 'object' && 'digitalCredential' in credential ? credential.originalVerifiableCredential! : credential, ) @@ -180,7 +190,7 @@ export class OID4VP { }).createVerifiablePresentation(vcs.definition.definition, verifiableCredentials, signCallback, { proofOptions, // fixme: Update to newer siop-vp to not require dids here. - holderDID: identifier.kid, + ...(idOpts.method !== 'oid4vci-issuer' && { holderDID: (await this.session.context.agent.identifierManagedGet(idOpts)).kid }) }) const verifiablePresentation = @@ -196,7 +206,7 @@ export class OID4VP { verifiablePresentation, verifiableCredentials: verifiableCredentials, definition: selectedVerifiableCredentials.definition, - idOpts: idOpts, + idOpts, } } @@ -303,7 +313,7 @@ export class OID4VP { return uniqueCredentials.map((uniqueVC: UniqueDigitalCredential) => { const vc = uniqueVC.uniformVerifiableCredential! const proof = Array.isArray(vc.proof) ? vc.proof : [vc.proof] - const jwtProof = proof.find((p) => p?.type === DEFAULT_JWT_PROOF_TYPE) + const jwtProof = proof.find((p: IProof) => p?.type === DEFAULT_JWT_PROOF_TYPE) return jwtProof ? (jwtProof.jwt as CompactJWT) : vc }) }