{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/modules/sd-jwt-vc/utils.ts"],"sourcesContent":["import type { Signer, Verifier } from '@sd-jwt/types'\nimport { AgentContext } from '../../agent'\nimport { CredoError } from '../../error'\nimport { TypedArrayEncoder } from '../../utils'\nimport { DidResolverService, DidsApi, getPublicJwkFromVerificationMethod, parseDid } from '../dids'\nimport { type Jwk, KeyManagementApi, PublicJwk } from '../kms'\nimport type { SdJwtVcHolderBinding } from './SdJwtVcOptions'\n\nexport async function resolveSigningPublicJwkFromDidUrl(agentContext: AgentContext, didUrl: string) {\n  const dids = agentContext.dependencyManager.resolve(DidsApi)\n\n  const { publicJwk } = await dids.resolveVerificationMethodFromCreatedDidRecord(didUrl)\n  return publicJwk\n}\n\nexport async function resolveDidUrl(agentContext: AgentContext, didUrl: string) {\n  const didResolver = agentContext.dependencyManager.resolve(DidResolverService)\n  const didDocument = await didResolver.resolveDidDocument(agentContext, didUrl)\n\n  return {\n    verificationMethod: didDocument.dereferenceKey(didUrl, ['assertionMethod']),\n    didDocument,\n  }\n}\n\nexport async function extractKeyFromHolderBinding(\n  agentContext: AgentContext,\n  holder: SdJwtVcHolderBinding,\n  { forSigning = false, jwkKeyId }: { forSigning?: boolean; jwkKeyId?: string } = {}\n) {\n  if (holder.method === 'did') {\n    const parsedDid = parseDid(holder.didUrl)\n    if (!parsedDid.fragment) {\n      throw new CredoError(`didUrl '${holder.didUrl}' does not contain a '#'. Unable to derive key from did document`)\n    }\n\n    let publicJwk: PublicJwk\n    if (forSigning) {\n      publicJwk = await resolveSigningPublicJwkFromDidUrl(agentContext, holder.didUrl)\n    } else {\n      const { verificationMethod } = await resolveDidUrl(agentContext, holder.didUrl)\n      publicJwk = getPublicJwkFromVerificationMethod(verificationMethod)\n    }\n\n    const supportedSignatureAlgorithms = publicJwk.supportedSignatureAlgorithms\n    if (supportedSignatureAlgorithms.length === 0) {\n      throw new CredoError(`No supported JWA signature algorithms found for key ${publicJwk.jwkTypeHumanDescription}`)\n    }\n    const alg = supportedSignatureAlgorithms[0]\n\n    return {\n      alg,\n      publicJwk,\n      cnf: {\n        // We need to include the whole didUrl here, otherwise the verifier\n        // won't know which did it is associated with\n        kid: holder.didUrl,\n      },\n    }\n  }\n  if (holder.method === 'jwk') {\n    const publicJwk = holder.jwk\n    const alg = publicJwk.supportedSignatureAlgorithms[0]\n\n    // FIXME: shouldn't we use `if (forSigning && !publicJwk.keyId)`, or at least use keyId over legacyKeyId\n    // It depends on whether we foresee security issues with trusting the `kid` field in the issued credential jwk.\n    // If there is no key id configured when signing, we assume this credential was issued before we included key ids\n    // and the we use the legacy key id.\n    if (forSigning) {\n      publicJwk.keyId = jwkKeyId ?? publicJwk.legacyKeyId\n    }\n\n    return {\n      alg,\n      publicJwk,\n      cnf: {\n        jwk: publicJwk.toJson(),\n      },\n    }\n  }\n\n  throw new CredoError(\"Unsupported credential holder binding. Only 'did' and 'jwk' are supported at the moment.\")\n}\n\n/**\n * @todo validate the JWT header (alg)\n */\nexport function getSdJwtSigner(agentContext: AgentContext, key: PublicJwk): Signer {\n  const kms = agentContext.resolve(KeyManagementApi)\n\n  return async (input: string) => {\n    const result = await kms.sign({\n      keyId: key.keyId,\n      data: TypedArrayEncoder.fromUtf8String(input),\n      algorithm: key.signatureAlgorithm,\n    })\n\n    return TypedArrayEncoder.toBase64Url(result.signature)\n  }\n}\n\n/**\n * @todo validate the JWT header (alg)\n */\nexport function getSdJwtVerifier(agentContext: AgentContext, key: PublicJwk): Verifier {\n  const kms = agentContext.resolve(KeyManagementApi)\n\n  return async (message: string, signatureBase64Url: string) => {\n    const result = await kms.verify({\n      signature: TypedArrayEncoder.fromBase64Url(signatureBase64Url),\n      key: {\n        publicJwk: key.toJson(),\n      },\n      data: TypedArrayEncoder.fromUtf8String(message),\n      algorithm: key.signatureAlgorithm,\n    })\n\n    return result.verified\n  }\n}\n\nexport interface CnfPayload {\n  jwk?: Jwk\n  kid?: string\n}\n\nexport function parseHolderBindingFromCredential(payload?: Record<string, unknown>): SdJwtVcHolderBinding | null {\n  if (!payload) {\n    throw new CredoError('Unable to extract payload from SD-JWT VC')\n  }\n\n  if (!payload.cnf) {\n    return null\n  }\n  const cnf: CnfPayload = payload.cnf\n\n  if (cnf.jwk) {\n    return {\n      method: 'jwk',\n      jwk: PublicJwk.fromUnknown(cnf.jwk),\n    }\n  }\n  if (cnf.kid) {\n    if (!cnf.kid.startsWith('did:') || !cnf.kid.includes('#')) {\n      throw new CredoError('Invalid holder kid for did. Only absolute KIDs for cnf are supported')\n    }\n    return {\n      method: 'did',\n      didUrl: cnf.kid,\n    }\n  }\n\n  throw new CredoError(\"Unsupported credential holder binding. Only 'did' and 'jwk' are supported at the moment.\")\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAQA,eAAsB,kCAAkC,cAA4B,QAAgB;CAGlG,MAAM,EAAE,cAAc,MAFT,aAAa,kBAAkB,QAAQ,QAAQ,CAE3B,8CAA8C,OAAO;AACtF,QAAO;;AAGT,eAAsB,cAAc,cAA4B,QAAgB;CAE9E,MAAM,cAAc,MADA,aAAa,kBAAkB,QAAQ,mBAAmB,CACxC,mBAAmB,cAAc,OAAO;AAE9E,QAAO;EACL,oBAAoB,YAAY,eAAe,QAAQ,CAAC,kBAAkB,CAAC;EAC3E;EACD;;AAGH,eAAsB,4BACpB,cACA,QACA,EAAE,aAAa,OAAO,aAA0D,EAAE,EAClF;AACA,KAAI,OAAO,WAAW,OAAO;AAE3B,MAAI,CADc,SAAS,OAAO,OAAO,CAC1B,SACb,OAAM,IAAI,WAAW,WAAW,OAAO,OAAO,kEAAkE;EAGlH,IAAI;AACJ,MAAI,WACF,aAAY,MAAM,kCAAkC,cAAc,OAAO,OAAO;OAC3E;GACL,MAAM,EAAE,uBAAuB,MAAM,cAAc,cAAc,OAAO,OAAO;AAC/E,eAAY,mCAAmC,mBAAmB;;EAGpE,MAAM,+BAA+B,UAAU;AAC/C,MAAI,6BAA6B,WAAW,EAC1C,OAAM,IAAI,WAAW,uDAAuD,UAAU,0BAA0B;AAIlH,SAAO;GACL,KAHU,6BAA6B;GAIvC;GACA,KAAK,EAGH,KAAK,OAAO,QACb;GACF;;AAEH,KAAI,OAAO,WAAW,OAAO;EAC3B,MAAM,YAAY,OAAO;EACzB,MAAM,MAAM,UAAU,6BAA6B;AAMnD,MAAI,WACF,WAAU,QAAQ,YAAY,UAAU;AAG1C,SAAO;GACL;GACA;GACA,KAAK,EACH,KAAK,UAAU,QAAQ,EACxB;GACF;;AAGH,OAAM,IAAI,WAAW,2FAA2F;;;;;AAMlH,SAAgB,eAAe,cAA4B,KAAwB;CACjF,MAAM,MAAM,aAAa,QAAQ,iBAAiB;AAElD,QAAO,OAAO,UAAkB;EAC9B,MAAM,SAAS,MAAM,IAAI,KAAK;GAC5B,OAAO,IAAI;GACX,MAAM,kBAAkB,eAAe,MAAM;GAC7C,WAAW,IAAI;GAChB,CAAC;AAEF,SAAO,kBAAkB,YAAY,OAAO,UAAU;;;;;;AAO1D,SAAgB,iBAAiB,cAA4B,KAA0B;CACrF,MAAM,MAAM,aAAa,QAAQ,iBAAiB;AAElD,QAAO,OAAO,SAAiB,uBAA+B;AAU5D,UATe,MAAM,IAAI,OAAO;GAC9B,WAAW,kBAAkB,cAAc,mBAAmB;GAC9D,KAAK,EACH,WAAW,IAAI,QAAQ,EACxB;GACD,MAAM,kBAAkB,eAAe,QAAQ;GAC/C,WAAW,IAAI;GAChB,CAAC,EAEY;;;AASlB,SAAgB,iCAAiC,SAAgE;AAC/G,KAAI,CAAC,QACH,OAAM,IAAI,WAAW,2CAA2C;AAGlE,KAAI,CAAC,QAAQ,IACX,QAAO;CAET,MAAM,MAAkB,QAAQ;AAEhC,KAAI,IAAI,IACN,QAAO;EACL,QAAQ;EACR,KAAK,UAAU,YAAY,IAAI,IAAI;EACpC;AAEH,KAAI,IAAI,KAAK;AACX,MAAI,CAAC,IAAI,IAAI,WAAW,OAAO,IAAI,CAAC,IAAI,IAAI,SAAS,IAAI,CACvD,OAAM,IAAI,WAAW,uEAAuE;AAE9F,SAAO;GACL,QAAQ;GACR,QAAQ,IAAI;GACb;;AAGH,OAAM,IAAI,WAAW,2FAA2F"}