UNPKG

@credo-ts/core

Version:

<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1

1 lines • 12.9 kB
{"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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"}