{"version":3,"file":"Mdoc.mjs","names":[],"sources":["../../../src/modules/mdoc/Mdoc.ts"],"sourcesContent":["import {\n  DeviceKey,\n  DeviceKeyInfo,\n  Holder,\n  Issuer,\n  IssuerSigned,\n  KeyAuthorizations,\n  SignatureAlgorithm,\n} from '@owf/mdoc'\nimport type { AgentContext } from '../../agent'\nimport { TrustedIssuerContext } from '../../agent/TrustedIssuerContext'\nimport { getMdocContext } from '../../crypto/contexts/mdocContext'\nimport { type KnownJwaSignatureAlgorithm, PublicJwk } from '../kms'\nimport { isKnownJwaSignatureAlgorithm } from '../kms/jwk/jwa'\nimport { ClaimFormat } from '../vc/index'\nimport { X509Certificate } from '../x509'\nimport { X509ModuleConfig } from '../x509/X509ModuleConfig'\nimport { MdocError } from './MdocError'\nimport type { MdocNameSpaces, MdocSignOptions, MdocVerifyOptions } from './MdocOptions'\nimport { isMdocSupportedSignatureAlgorithm, mdocSupportedSignatureAlgorithms } from './mdocSupportedAlgs'\nimport {\n  assertMdocStatusListChainsMatchIssuanceChain,\n  convertMdocTrustedCertificates,\n  mdocTrustedCertificatesToRaw,\n} from './mdocUtil'\n\n/**\n * This class represents a IssuerSigned Mdoc Document,\n * which are the actual credentials being issued to holders.\n */\nexport class Mdoc {\n  public get base64Url() {\n    return this.issuerSigned.encodedForOid4Vci\n  }\n\n  #deviceKeyId?: string\n\n  public constructor(public issuerSigned: IssuerSigned) {}\n\n  /**\n   * claim format is convenience method added to all credential instances\n   */\n  public get claimFormat() {\n    return ClaimFormat.MsoMdoc as const\n  }\n\n  /**\n   * Encoded is convenience method added to all credential instances\n   */\n  public get encoded() {\n    return this.issuerSigned.encodedForOid4Vci\n  }\n\n  /**\n   * Get the device key to which the mdoc is bound\n   */\n  public get deviceKey(): PublicJwk {\n    const publicJwk = PublicJwk.fromUnknown(\n      this.issuerSigned.issuerAuth.mobileSecurityObject.deviceKeyInfo.deviceKey.jwk\n    )\n\n    if (this.#deviceKeyId) publicJwk.keyId = this.#deviceKeyId\n    return publicJwk\n  }\n\n  public set deviceKeyId(keyId: string | undefined) {\n    this.#deviceKeyId = keyId\n  }\n\n  public get deviceKeyId() {\n    const deviceKey = this.deviceKey\n\n    if (deviceKey.hasKeyId) return deviceKey.keyId\n    return undefined\n  }\n\n  public static fromBase64Url(mdocBase64Url: string): Mdoc {\n    const issuerSigned = IssuerSigned.fromEncodedForOid4Vci(mdocBase64Url)\n    return new Mdoc(issuerSigned)\n  }\n\n  public get docType(): string {\n    return this.issuerSigned.issuerAuth.mobileSecurityObject.docType\n  }\n\n  public get alg(): KnownJwaSignatureAlgorithm {\n    const jwaAlg = this.issuerSigned.issuerAuth.jwaAlgorithm\n\n    if (!jwaAlg) {\n      throw new MdocError('The IssuerAuth does not have a valid signature algorithm in the header')\n    }\n\n    if (isKnownJwaSignatureAlgorithm(jwaAlg)) {\n      return jwaAlg\n    }\n\n    throw new MdocError(`Cannot parse mdoc. The signature algorithm '${jwaAlg}' is not supported.`)\n  }\n\n  public get validityInfo() {\n    const { signed, validFrom, validUntil } = this.issuerSigned.issuerAuth.mobileSecurityObject.validityInfo\n    return {\n      signed,\n      validFrom,\n      validUntil,\n    }\n  }\n\n  public get issuerSignedCertificateChain() {\n    return this.issuerSigned.issuerAuth.certificateChain\n  }\n\n  public get signingCertificate() {\n    return this.issuerSigned.issuerAuth.certificate\n  }\n\n  public get issuerSignedNamespaces(): MdocNameSpaces {\n    if (!this.issuerSigned.issuerNamespaces?.issuerNamespaces) return {}\n\n    return Object.fromEntries(\n      Array.from(this.issuerSigned.issuerNamespaces.issuerNamespaces.entries()).map(([namespace, value]) => [\n        namespace,\n        Object.fromEntries(Array.from(value.values()).map((v) => [v.elementIdentifier, v.elementValue])),\n      ])\n    )\n  }\n\n  public static async sign(agentContext: AgentContext, options: MdocSignOptions) {\n    const { docType, validityInfo, namespaces, holderKey, issuerCertificate, keyAuthorizations } = options\n    const mdocContext = getMdocContext(agentContext)\n\n    const issuer = new Issuer(docType, mdocContext)\n\n    for (const [namespace, namespaceRecord] of Object.entries(namespaces)) {\n      issuer.addIssuerNamespace(namespace, namespaceRecord)\n    }\n\n    const issuerKey = Array.isArray(issuerCertificate) ? issuerCertificate[0].publicJwk : issuerCertificate.publicJwk\n    const alg = issuerKey.supportedSignatureAlgorithms.find(isMdocSupportedSignatureAlgorithm)\n    if (!alg) {\n      throw new MdocError(\n        `Unable to create sign mdoc. No supported signature algorithm found to sign mdoc for jwk with key ${\n          issuerKey.jwkTypeHumanDescription\n        }. Key supports algs ${issuerKey.supportedSignatureAlgorithms.join(\n          ', '\n        )}. mdoc supports algs ${mdocSupportedSignatureAlgorithms.join(', ')}`\n      )\n    }\n\n    const now = new Date()\n    const issuerSigned = await issuer.sign({\n      digestAlgorithm: 'SHA-256',\n      validityInfo: {\n        ...validityInfo,\n        signed: validityInfo.signed ?? now,\n        validFrom: validityInfo.validFrom ?? now,\n      },\n      algorithm: SignatureAlgorithm[alg],\n      certificates: Array.isArray(issuerCertificate)\n        ? issuerCertificate.map((c) => c.rawCertificate)\n        : [issuerCertificate.rawCertificate],\n      deviceKeyInfo: DeviceKeyInfo.create({\n        deviceKey: DeviceKey.fromJwk(holderKey.toJson()),\n        keyAuthorizations: keyAuthorizations\n          ? KeyAuthorizations.create({\n              namespaces: keyAuthorizations.namespaces,\n              dataElements: keyAuthorizations.dataElements\n                ? new Map(Object.entries(keyAuthorizations.dataElements))\n                : undefined,\n            })\n          : undefined,\n      }),\n      signingKey: issuerKey.toJson(),\n      status: options.statusInfo\n        ? {\n            statusList: {\n              idx: options.statusInfo.index,\n              uri: options.statusInfo.uri,\n              certificate: options.statusInfo.certificate?.rawCertificate,\n            },\n          }\n        : undefined,\n    })\n\n    return new Mdoc(issuerSigned)\n  }\n\n  public async verify(\n    agentContext: AgentContext,\n    options?: MdocVerifyOptions\n  ): Promise<{ isValid: true } | { isValid: false; error: string }> {\n    const x509ModuleConfig = agentContext.dependencyManager.resolve(X509ModuleConfig)\n    const certificateChain = this.issuerSigned.issuerAuth.certificateChain.map((certificate) =>\n      X509Certificate.fromRawCertificate(certificate)\n    )\n\n    let trustedCertificates = options?.trustedCertificates\n    if (!trustedCertificates) {\n      const trustedIssuers = await TrustedIssuerContext.getTrustedIssuersForVerification(agentContext, {\n        verification: { type: 'credential', credential: this },\n        signer: {\n          certificateChain,\n          method: 'x509',\n        },\n      })\n\n      trustedCertificates =\n        trustedIssuers?.trustedIssuers ??\n        (await x509ModuleConfig.getTrustedCertificatesForVerification?.(agentContext, {\n          verification: {\n            type: 'credential',\n            credential: this,\n          },\n          certificateChain,\n        })) ??\n        x509ModuleConfig.trustedCertificates\n    }\n\n    if (!trustedCertificates) {\n      throw new MdocError('No trusted certificates found. Cannot verify mdoc.')\n    }\n\n    const mdocContext = getMdocContext(agentContext, {\n      now: options?.now,\n    })\n\n    try {\n      const convertedTrustedCertificates = convertMdocTrustedCertificates(trustedCertificates)\n\n      const { trustedIssuanceChain, trustedStatusListChain, trustedIdentifierListChain } =\n        await Holder.verifyIssuerSigned(\n          {\n            trustedCertificates: mdocTrustedCertificatesToRaw(convertedTrustedCertificates),\n            issuerSigned: this.issuerSigned,\n            disableCertificateChainValidation: false,\n            disableStatusValidation: false,\n            now: options?.now,\n          },\n          mdocContext\n        )\n\n      // Only undefined without chain validation, which is never disabled here.\n      if (!trustedIssuanceChain) {\n        throw new MdocError('Unable to determine a trusted issuance chain')\n      }\n\n      const issuanceChain = trustedIssuanceChain.map((c) => X509Certificate.fromRawCertificate(c))\n\n      // The mdoc x5chain is leaf-first and does not include the trust anchor. The validated chain returned by\n      // the library is leaf-first with the resolved trust anchor appended, so the mdoc chain must equal its leaf-end prefix.\n      const certificateChainMatchesIssuanceChain =\n        certificateChain.length <= issuanceChain.length &&\n        certificateChain.every((cert, i) => cert.equal(issuanceChain[i]))\n      if (!certificateChainMatchesIssuanceChain) {\n        throw new MdocError('Certificate chain does not match the trusted issuance chain')\n      }\n\n      assertMdocStatusListChainsMatchIssuanceChain(convertedTrustedCertificates, {\n        trustedIssuanceChain,\n        trustedStatusListChain,\n        trustedIdentifierListChain,\n      })\n\n      return { isValid: true }\n    } catch (error) {\n      return { isValid: false, error: error.message }\n    }\n  }\n}\n"],"mappings":"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"}