{"version":3,"file":"mdocUtil.mjs","names":[],"sources":["../../../src/modules/mdoc/mdocUtil.ts"],"sourcesContent":["import { DeviceNamespaces, DeviceSignedItems } from '@owf/mdoc'\nimport type { PublicJwk } from '../kms'\nimport { convertLegacyTrustedCertificates } from '../x509/utils/convertLegacyTrustedCertificates'\nimport { X509Certificate } from '../x509/X509Certificate'\nimport type { X509VerificationTrustedCertificates } from '../x509/X509ModuleConfig'\nimport { MdocError } from './MdocError'\nimport type { MdocNameSpaces } from './MdocOptions'\nimport { isMdocSupportedSignatureAlgorithm, mdocSupportedSignatureAlgorithms } from './mdocSupportedAlgs'\n\n/**\n * mdoc COSE structures require an explicit `alg`, but credo public JWKs generally don't carry one.\n */\nexport function getMdocSignatureAlgForJwk(publicJwk: PublicJwk) {\n  const signatureAlgorithm = publicJwk.supportedSignatureAlgorithms.find(isMdocSupportedSignatureAlgorithm)\n  if (!signatureAlgorithm) {\n    throw new MdocError(\n      `No supported signature algorithm found for jwk ${\n        publicJwk.jwkTypeHumanDescription\n      }. Key supports algs ${publicJwk.supportedSignatureAlgorithms.join(\n        ', '\n      )}. mdoc supports algs ${mdocSupportedSignatureAlgorithms.join(', ')}`\n    )\n  }\n\n  return signatureAlgorithm\n}\n\n/**\n * The JSON representation of a public JWK, with `alg` filled in as the mdoc COSE structures require\n * it. The `kid` (needed to resolve the key for signing) is taken from the jwk as-is; it's up to the\n * caller to make sure the key id is set.\n */\nexport function mdocSigningJwk(publicJwk: PublicJwk) {\n  const jwk = publicJwk.toJson()\n\n  return {\n    ...jwk,\n    alg: jwk.alg ?? getMdocSignatureAlgForJwk(publicJwk),\n  }\n}\n\nexport interface MdocTrustedCertificate {\n  issuance: string[]\n  status: string[]\n  hasDedicatedStatusCertificates: boolean\n}\n\n/**\n * Falls back to the `issuance` certs when no `status` certs are configured (`status: undefined`); an\n * explicit `status: []` is passed through. {@link assertMdocStatusListChainsMatchIssuanceChain} then\n * keeps the fallback from widening the trust set.\n */\nexport function convertMdocTrustedCertificates(\n  trustedCertificates: string[] | X509VerificationTrustedCertificates[]\n): MdocTrustedCertificate[] {\n  return convertLegacyTrustedCertificates(trustedCertificates).map(({ issuance, status }) => ({\n    issuance,\n    status: status ?? issuance,\n    hasDedicatedStatusCertificates: status !== undefined,\n  }))\n}\n\n/**\n * Maps the converted trusted certificates to the raw representation the `@owf/mdoc` library expects.\n */\nexport function mdocTrustedCertificatesToRaw(trustedCertificates: MdocTrustedCertificate[]) {\n  return trustedCertificates.map(({ issuance, status }) => ({\n    issuance: issuance.map((cert) => X509Certificate.fromEncodedCertificate(cert).rawCertificate),\n    status: status.map((cert) => X509Certificate.fromEncodedCertificate(cert).rawCertificate),\n  }))\n}\n\n/**\n * Without dedicated status certs, requires the status/identifier list chains to equal the issuance\n * chain, so the fallback can't accept a list signed by a different chain under the same trust anchor.\n */\nexport function assertMdocStatusListChainsMatchIssuanceChain(\n  trustedCertificates: MdocTrustedCertificate[],\n  chains: {\n    trustedIssuanceChain: Uint8Array[]\n    trustedStatusListChain?: Uint8Array[]\n    trustedIdentifierListChain?: Uint8Array[]\n  }\n) {\n  const issuanceChain = chains.trustedIssuanceChain.map((cert) => X509Certificate.fromRawCertificate(cert))\n  const issuanceTrustAnchor = issuanceChain[issuanceChain.length - 1]\n\n  const matchedTrustedCertificate = trustedCertificates.find(({ issuance }) =>\n    issuance.some((cert) => X509Certificate.fromEncodedCertificate(cert).equal(issuanceTrustAnchor))\n  )\n\n  // With dedicated status certs the library already validated the lists against them.\n  if (matchedTrustedCertificate?.hasDedicatedStatusCertificates) return\n\n  const chainMatchesIssuanceChain = (chain: Uint8Array[]) => {\n    const resolvedChain = chain.map((cert) => X509Certificate.fromRawCertificate(cert))\n    return (\n      resolvedChain.length === issuanceChain.length && resolvedChain.every((cert, i) => cert.equal(issuanceChain[i]))\n    )\n  }\n\n  if (chains.trustedIdentifierListChain && !chainMatchesIssuanceChain(chains.trustedIdentifierListChain)) {\n    throw new MdocError(\n      'Trusted identifier list chain does not match the trusted issuance chain, and no trusted status certificates were provided for the trusted issuance certificate'\n    )\n  }\n\n  if (chains.trustedStatusListChain && !chainMatchesIssuanceChain(chains.trustedStatusListChain)) {\n    throw new MdocError(\n      'Trusted status list chain does not match the trusted issuance chain, and no trusted status certificates were provided for the trusted issuance certificate'\n    )\n  }\n}\n\nexport function nameSpacesRecordToMap<\n  NamespaceValue,\n  NameSpaces extends Record<string, Record<string, NamespaceValue>>,\n>(nameSpaces: NameSpaces): Map<string, Map<string, NamespaceValue>> {\n  return new Map(Object.entries(nameSpaces).map(([key, value]) => [key, new Map(Object.entries(value))] as const))\n}\n\nexport function nameSpacesRecordToDeviceNamespaces(nameSpaces: MdocNameSpaces) {\n  return DeviceNamespaces.create({\n    deviceNamespaces: new Map(\n      Array.from(nameSpacesRecordToMap(nameSpaces), ([nameSpace, items]) => [\n        nameSpace,\n        DeviceSignedItems.create({ deviceSignedItems: items }),\n      ])\n    ),\n  })\n}\n\nexport function namespacesMapToRecord<NamespaceValue, NameSpaces extends Map<string, Map<string, NamespaceValue>>>(\n  nameSpaces: NameSpaces\n): Record<string, Record<string, NamespaceValue>> {\n  return Object.fromEntries(\n    Array.from(nameSpaces.entries()).map(([key, value]) => [key, Object.fromEntries(Array.from(value.entries()))])\n  )\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,0BAA0B,WAAsB;CAC9D,MAAM,qBAAqB,UAAU,6BAA6B,KAAK,iCAAiC;CACxG,IAAI,CAAC,oBACH,MAAM,IAAI,UACR,kDACE,UAAU,wBACX,sBAAsB,UAAU,6BAA6B,KAC5D,IACF,EAAE,uBAAuB,iCAAiC,KAAK,IAAI,GACrE;CAGF,OAAO;AACT;;;;;;AAOA,SAAgB,eAAe,WAAsB;CACnD,MAAM,MAAM,UAAU,OAAO;CAE7B,OAAO;EACL,GAAG;EACH,KAAK,IAAI,OAAO,0BAA0B,SAAS;CACrD;AACF;;;;;;AAaA,SAAgB,+BACd,qBAC0B;CAC1B,OAAO,iCAAiC,mBAAmB,CAAC,CAAC,KAAK,EAAE,UAAU,cAAc;EAC1F;EACA,QAAQ,UAAU;EAClB,gCAAgC,WAAW,KAAA;CAC7C,EAAE;AACJ;;;;AAKA,SAAgB,6BAA6B,qBAA+C;CAC1F,OAAO,oBAAoB,KAAK,EAAE,UAAU,cAAc;EACxD,UAAU,SAAS,KAAK,SAAS,gBAAgB,uBAAuB,IAAI,CAAC,CAAC,cAAc;EAC5F,QAAQ,OAAO,KAAK,SAAS,gBAAgB,uBAAuB,IAAI,CAAC,CAAC,cAAc;CAC1F,EAAE;AACJ;;;;;AAMA,SAAgB,6CACd,qBACA,QAKA;CACA,MAAM,gBAAgB,OAAO,qBAAqB,KAAK,SAAS,gBAAgB,mBAAmB,IAAI,CAAC;CACxG,MAAM,sBAAsB,cAAc,cAAc,SAAS;CAOjE,IALkC,oBAAoB,MAAM,EAAE,eAC5D,SAAS,MAAM,SAAS,gBAAgB,uBAAuB,IAAI,CAAC,CAAC,MAAM,mBAAmB,CAAC,CAIrE,CAAC,EAAE,gCAAgC;CAE/D,MAAM,6BAA6B,UAAwB;EACzD,MAAM,gBAAgB,MAAM,KAAK,SAAS,gBAAgB,mBAAmB,IAAI,CAAC;EAClF,OACE,cAAc,WAAW,cAAc,UAAU,cAAc,OAAO,MAAM,MAAM,KAAK,MAAM,cAAc,EAAE,CAAC;CAElH;CAEA,IAAI,OAAO,8BAA8B,CAAC,0BAA0B,OAAO,0BAA0B,GACnG,MAAM,IAAI,UACR,gKACF;CAGF,IAAI,OAAO,0BAA0B,CAAC,0BAA0B,OAAO,sBAAsB,GAC3F,MAAM,IAAI,UACR,4JACF;AAEJ;AAEA,SAAgB,sBAGd,YAAkE;CAClE,OAAO,IAAI,IAAI,OAAO,QAAQ,UAAU,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,IAAI,IAAI,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAU,CAAC;AACjH;AAEA,SAAgB,mCAAmC,YAA4B;CAC7E,OAAO,iBAAiB,OAAO,EAC7B,kBAAkB,IAAI,IACpB,MAAM,KAAK,sBAAsB,UAAU,IAAI,CAAC,WAAW,WAAW,CACpE,WACA,kBAAkB,OAAO,EAAE,mBAAmB,MAAM,CAAC,CACvD,CAAC,CACH,EACF,CAAC;AACH"}