@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 • 20.3 kB
Source Map (JSON)
{"version":3,"file":"MdocDeviceResponse.mjs","names":[],"sources":["../../../src/modules/mdoc/MdocDeviceResponse.ts"],"sourcesContent":["import {\n CoseKey,\n DeviceNamespaces,\n DeviceRequest,\n DeviceResponse,\n DeviceSignedItems,\n DocRequest,\n Document,\n defaultVerificationCallback,\n IssuerNamespaces,\n ItemsRequest,\n limitDisclosureToDeviceRequestNameSpaces,\n type MdocContext,\n SessionTranscript,\n} from '@owf/mdoc'\nimport type { InputDescriptorV2 } from '@sphereon/pex-models'\nimport {\n convertDcqlQueryToDeviceRequest,\n convertPresentationDefinitionToDeviceRequest,\n type Field,\n type PresentationDefinition,\n} from '@verifiables/request-converter'\nimport { AgentContext } from '../../agent'\nimport { TypedArrayEncoder } from './../../utils'\nimport { PublicJwk } from '../kms'\nimport { ClaimFormat } from '../vc'\nimport { X509Certificate } from '../x509'\nimport type { Mdoc } from './Mdoc'\nimport { getMdocContext } from './MdocContext'\nimport { MdocError } from './MdocError'\nimport type {\n MdocDeviceResponseDcqlQueryOptions,\n MdocDeviceResponseOptions,\n MdocDeviceResponsePresentationDefinitionOptions,\n MdocDeviceResponseVerifyOptions,\n MdocSessionTranscriptOptions,\n} from './MdocOptions'\nimport { isMdocSupportedSignatureAlgorithm, mdocSupportedSignatureAlgorithms } from './mdocSupportedAlgs'\nimport { nameSpacesRecordToMap } from './mdocUtil'\nimport { convertDocumentRequest } from './utils/convertDocumentRequest'\n\nexport type DeviceAndIssuerClaims = {\n [docType: string]: {\n [namespace: string]: {\n [claimIdentifier: string]: unknown\n }\n }\n}\n\nexport class MdocDeviceResponse {\n private constructor(public readonly deviceResponse: DeviceResponse) {}\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 TypedArrayEncoder.toBase64Url(this.deviceResponse.encode())\n }\n\n /**\n * To support a single DeviceResponse with multiple documents in OpenID4VP\n */\n public splitIntoSingleDocumentResponses(): MdocDeviceResponse[] {\n const deviceResponses: MdocDeviceResponse[] = []\n\n if (!this.deviceResponse.documents || this.deviceResponse.documents.length === 0) {\n throw new MdocError('mdoc device response does not contain any mdocs')\n }\n\n for (const document of this.deviceResponse.documents) {\n deviceResponses.push(\n new MdocDeviceResponse(\n DeviceResponse.createSimple({\n version: this.deviceResponse.version,\n status: this.deviceResponse.status,\n documentErrors: this.deviceResponse.documentErrors,\n documents: [document],\n })\n )\n )\n }\n\n return deviceResponses\n }\n\n public static fromBase64Url(base64Url: string) {\n const parsed = DeviceResponse.decode(TypedArrayEncoder.fromBase64Url(base64Url))\n\n return new MdocDeviceResponse(parsed)\n }\n\n public static async createDeviceResponseWithPresentationDefinition(\n agentContext: AgentContext,\n options: MdocDeviceResponsePresentationDefinitionOptions\n ) {\n // @ts-expect-error: we need to match the types credo uses and the converter expects\n const { deviceRequest } = convertPresentationDefinitionToDeviceRequest(options.presentationDefinition)\n const documentRequests = convertDocumentRequest(deviceRequest.docRequests)\n\n return MdocDeviceResponse.createDeviceResponse(agentContext, { ...options, documentRequests })\n }\n\n public static async createDeviceResponseWithDcqlQuery(\n agentContext: AgentContext,\n options: MdocDeviceResponseDcqlQueryOptions\n ) {\n // @ts-expect-error: we need to match the types credo uses and the converter expects\n const { deviceRequest } = convertDcqlQueryToDeviceRequest(options.dcqlQuery)\n const documentRequests = convertDocumentRequest(deviceRequest.docRequests)\n\n return MdocDeviceResponse.createDeviceResponse(agentContext, { ...options, documentRequests })\n }\n\n public static async limitDisclosureToInputDescriptor(\n _agentContext: AgentContext,\n { mdoc, ...options }: { inputDescriptor: InputDescriptorV2; mdoc: Mdoc }\n ) {\n const inputDescriptor = MdocDeviceResponse.assertMdocInputDescriptor(options.inputDescriptor)\n\n let issuerNamespaces: IssuerNamespaces | undefined\n\n // First we try with all optional fields enabled, if that results in an error during the `limitDisclosureToDeviceRequestNameSpaces` call, we try again, skipping all optional fields\n try {\n // We take the first document request as we also only input a single input descriptor\n const {\n deviceRequest: {\n docRequests: [convertedDocumentRequest],\n },\n } = convertPresentationDefinitionToDeviceRequest({\n id: '<UNUSED_CREDO_ID>',\n input_descriptors: [inputDescriptor],\n })\n\n const documentRequest = DocRequest.create({\n itemsRequest: ItemsRequest.create({\n docType: convertedDocumentRequest.itemsRequest.docType,\n namespaces: convertedDocumentRequest.itemsRequest.nameSpaces,\n }),\n })\n\n issuerNamespaces = limitDisclosureToDeviceRequestNameSpaces(mdoc.issuerSigned, documentRequest)\n } catch (_error) {\n // We take the first document request as we also only input a single input descriptor\n const {\n deviceRequest: {\n docRequests: [convertedDocumentRequest],\n },\n } = convertPresentationDefinitionToDeviceRequest(\n {\n id: '<UNUSED_CREDO_ID>',\n input_descriptors: [inputDescriptor],\n },\n { skipOptionalFields: true }\n )\n\n const documentRequest = DocRequest.create({\n itemsRequest: ItemsRequest.create({\n docType: convertedDocumentRequest.itemsRequest.docType,\n namespaces: convertedDocumentRequest.itemsRequest.nameSpaces,\n }),\n })\n\n issuerNamespaces = limitDisclosureToDeviceRequestNameSpaces(mdoc.issuerSigned, documentRequest)\n }\n\n const disclosedPayloadAsRecord = Object.fromEntries(\n Array.from(issuerNamespaces.issuerNamespaces.entries()).map(([namespace, issuerSignedItem]) => [\n namespace,\n Object.fromEntries(issuerSignedItem.map((isi) => [isi.elementIdentifier, isi.elementValue])),\n ])\n )\n\n return disclosedPayloadAsRecord\n }\n\n private static assertMdocInputDescriptor(inputDescriptor: InputDescriptorV2) {\n if (!inputDescriptor.format || !inputDescriptor.format.mso_mdoc) {\n throw new MdocError(`Input descriptor must contain 'mso_mdoc' format property`)\n }\n\n if (!inputDescriptor.format.mso_mdoc.alg) {\n throw new MdocError(`Input descriptor mso_mdoc must contain 'alg' property`)\n }\n\n if (!inputDescriptor.constraints?.limit_disclosure || inputDescriptor.constraints.limit_disclosure !== 'required') {\n throw new MdocError(\n `Input descriptor must contain 'limit_disclosure' constraints property which is set to required`\n )\n }\n\n if (!inputDescriptor.constraints?.fields?.every((field) => field.intent_to_retain !== undefined)) {\n throw new MdocError(`Input descriptor must contain 'intent_to_retain' constraints property`)\n }\n\n return {\n ...inputDescriptor,\n format: {\n mso_mdoc: inputDescriptor.format.mso_mdoc,\n },\n constraints: {\n ...inputDescriptor.constraints,\n limit_disclosure: 'required',\n fields: (inputDescriptor.constraints.fields ?? []).map((field) => {\n return {\n ...field,\n intent_to_retain: field.intent_to_retain ?? false,\n }\n }) as Field[],\n },\n } satisfies PresentationDefinition['input_descriptors'][number]\n }\n\n public static async createDeviceResponse(agentContext: AgentContext, options: MdocDeviceResponseOptions) {\n const documents: Document[] = []\n\n for (const document of options.mdocs) {\n const deviceKeyJwk = document.deviceKey\n const deviceKeyJwkJson = deviceKeyJwk.toJson()\n\n if (!deviceKeyJwkJson.alg) {\n // FIXME: we cannot provide alg anymore?\n deviceKeyJwkJson.alg = MdocDeviceResponse.getAlgForDeviceKeyJwk(deviceKeyJwk)\n }\n\n // Set keyId to legacy key id if it doesn't have a key id set\n if (!deviceKeyJwk.hasKeyId) {\n deviceKeyJwk.keyId = deviceKeyJwk.legacyKeyId\n }\n\n const deviceRequestForDocument = DeviceRequest.create({\n version: '1.0',\n docRequests: options.documentRequests\n .filter((request) => request.docType === document.docType)\n .map((request) =>\n DocRequest.create({\n itemsRequest: ItemsRequest.create({\n docType: request.docType,\n namespaces: nameSpacesRecordToMap(request.nameSpaces),\n }),\n })\n ),\n })\n\n const mdocContext = getMdocContext(agentContext)\n const deviceResponse = await DeviceResponse.createWithDeviceRequest(\n {\n deviceRequest: deviceRequestForDocument,\n issuerSigned: [document.issuerSigned],\n sessionTranscript: await MdocDeviceResponse.calculateSessionTranscriptBytes(\n mdocContext,\n options.sessionTranscriptOptions\n ),\n deviceNamespaces: options.deviceNameSpaces\n ? DeviceNamespaces.create({\n deviceNamespaces: new Map(\n Object.entries(options.deviceNameSpaces).map(([namespace, namespaceValue]) => [\n namespace,\n DeviceSignedItems.create({\n deviceSignedItems: new Map(Object.entries(namespaceValue)),\n }),\n ])\n ),\n })\n : undefined,\n signature: {\n signingKey: CoseKey.fromJwk(deviceKeyJwk.toJson()),\n },\n },\n mdocContext\n )\n\n if (!deviceResponse.documents) {\n throw new MdocError('Device response does not contain any documents')\n }\n documents.push(deviceResponse.documents[0])\n }\n\n return new MdocDeviceResponse(\n DeviceResponse.createSimple({\n version: '1.0',\n documents,\n })\n )\n }\n\n public async verify(agentContext: AgentContext, options: Omit<MdocDeviceResponseVerifyOptions, 'deviceResponse'>) {\n const mdocContext = getMdocContext(agentContext)\n\n defaultVerificationCallback({\n status: this.deviceResponse.documents?.length ? 'PASSED' : 'FAILED',\n check: 'Device Response must include at least one document.',\n category: 'DOCUMENT_FORMAT',\n })\n\n await this.deviceResponse\n .verify(\n {\n trustedCertificates:\n options.trustedCertificates?.map(\n (certificate) => X509Certificate.fromEncodedCertificate(certificate).rawCertificate\n ) ?? [],\n disableCertificateChainValidation: false,\n now: options.now,\n skewSeconds: agentContext.config.validitySkewSeconds,\n sessionTranscript: await MdocDeviceResponse.calculateSessionTranscriptBytes(\n mdocContext,\n options.sessionTranscriptOptions\n ),\n },\n mdocContext\n )\n .catch((error) => {\n throw new MdocError(`Mdoc with doctype ${this.deviceResponse.documents?.[0].docType} is not valid`, {\n cause: error,\n })\n })\n }\n\n private static async calculateSessionTranscriptBytes(\n mdocContext: MdocContext,\n options: MdocSessionTranscriptOptions\n ) {\n if (options.type === 'sesionTranscriptBytes') {\n return options.sessionTranscriptBytes\n }\n\n if (options.type === 'openId4VpDraft18') {\n return SessionTranscript.forOid4VpDraft18(options, mdocContext)\n }\n\n if (options.type === 'openId4Vp') {\n const { encryptionJwk, verifierGeneratedNonce, ...rest } = options\n return SessionTranscript.forOid4Vp(\n {\n ...rest,\n jwkThumbprint: encryptionJwk ? encryptionJwk.getJwkThumbprint() : undefined,\n nonce: verifierGeneratedNonce,\n },\n mdocContext\n )\n }\n\n if (options.type === 'openId4VpDcApi') {\n const { encryptionJwk, verifierGeneratedNonce, ...rest } = options\n return SessionTranscript.forOid4VpDcApi(\n {\n ...rest,\n nonce: verifierGeneratedNonce,\n jwkThumbprint: encryptionJwk ? encryptionJwk.getJwkThumbprint() : undefined,\n },\n mdocContext\n )\n }\n\n if (options.type === 'openId4VpDcApiDraft24') {\n const { verifierGeneratedNonce, ...rest } = options\n\n return SessionTranscript.forOid4VpDcApiDraft24(\n {\n ...rest,\n nonce: verifierGeneratedNonce,\n },\n mdocContext\n )\n }\n\n throw new MdocError('Unsupported session transcript option')\n }\n\n private static getAlgForDeviceKeyJwk(jwk: PublicJwk) {\n const signatureAlgorithm = jwk.supportedSignatureAlgorithms.find(isMdocSupportedSignatureAlgorithm)\n if (!signatureAlgorithm) {\n throw new MdocError(\n `Unable to create mdoc device response. No supported signature algorithm found to sign device response for jwk ${\n jwk.jwkTypeHumanDescription\n }. Key supports algs ${jwk.supportedSignatureAlgorithms.join(\n ', '\n )}. mdoc supports algs ${mdocSupportedSignatureAlgorithms.join(', ')}`\n )\n }\n\n return signatureAlgorithm\n }\n\n public get issuerClaims(): DeviceAndIssuerClaims {\n if (!this.deviceResponse.documents) return {}\n\n return this.deviceResponse.documents.reduce(\n (prev, document) => ({\n // biome-ignore lint/performance/noAccumulatingSpread: time complexity is not relevant here\n ...prev,\n [document.docType]: Object.fromEntries(\n Array.from(document.issuerSigned.issuerNamespaces.issuerNamespaces.entries()).map(([namespace, claim]) => [\n namespace,\n Object.fromEntries(claim.map((c) => [c.elementIdentifier, c.elementValue])),\n ])\n ),\n }),\n {}\n )\n }\n\n public get deviceClaims(): DeviceAndIssuerClaims {\n if (!this.deviceResponse.documents) return {}\n\n return this.deviceResponse.documents.reduce(\n (prev, document) => ({\n // biome-ignore lint/performance/noAccumulatingSpread: time complexity is not relevant here\n ...prev,\n [document.docType]: Object.fromEntries(\n Array.from(document.deviceSigned.deviceNamespaces.deviceNamespaces.entries()).map(([namespace, claim]) => [\n namespace,\n Object.fromEntries(claim.deviceSignedItems),\n ])\n ),\n }),\n {}\n )\n }\n}\n"],"mappings":"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"}