@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 • 8.53 kB
Source Map (JSON)
{"version":3,"file":"mdocContext.mjs","names":[],"sources":["../../../src/crypto/contexts/mdocContext.ts"],"sourcesContent":["import { CoseKey, type HpkeSuiteId, type MdocContext } from '@owf/mdoc'\nimport { AgentContext } from '../../agent'\nimport { CredoWebCrypto } from '../../crypto'\nimport { CredoError } from '../../error'\nimport { KeyManagementApi, type KmsJwkPublicEcdh, type KnownJwaHpkeAlgorithm, PublicJwk } from '../../modules/kms'\nimport { X509Certificate } from '../../modules/x509/X509Certificate'\nimport { X509Service } from '../../modules/x509/X509Service'\nimport { getMac0Context } from './mac0Context'\nimport { getSign1Context } from './sign1Context'\n\n/**\n * HPKE suites the mdoc library can request, mapped to the JOSE-HPKE style algorithm identifiers the\n * KMS uses. ISO 18013-7 Annex C only uses the first entry.\n */\nconst hpkeSuiteToJwaAlgorithm = {\n 'dhkem-p256-hkdf-sha256/hkdf-sha256/aes-128-gcm': 'HPKE-0',\n 'dhkem-p256-hkdf-sha256/hkdf-sha256/aes-256-gcm': 'HPKE-7',\n 'dhkem-x25519-hkdf-sha256/hkdf-sha256/aes-128-gcm': 'HPKE-3',\n} as const satisfies Record<HpkeSuiteId, KnownJwaHpkeAlgorithm>\n\nfunction jwaAlgorithmForHpkeSuite(suite: HpkeSuiteId) {\n const algorithm = hpkeSuiteToJwaAlgorithm[suite]\n if (!algorithm) throw new CredoError(`Unsupported HPKE suite '${suite}'`)\n\n return algorithm\n}\n\nexport const getMdocContext = (agentContext: AgentContext, { now }: { now?: Date } = {}): MdocContext => {\n const crypto = new CredoWebCrypto(agentContext)\n const kms = agentContext.resolve(KeyManagementApi)\n\n return {\n fetch: agentContext.config.agentDependencies.fetch,\n crypto: {\n digest: async (input) => {\n const { bytes, digestAlgorithm } = input\n\n return new Uint8Array(\n crypto.digest(\n digestAlgorithm,\n // NOTE: extra Uint8Array wrapping is needed here, somehow if we use `bytes.buffer` directly\n // it's not working. Maybe due to Uint8array length\n new Uint8Array(bytes).buffer\n )\n )\n },\n random: (length) => {\n return crypto.getRandomValues(new Uint8Array(length))\n },\n hdkf: async () => {\n // Only invoked for mdoc device MAC authentication (ISO/IEC 18013-5), which Credo does not\n // implement (device signature authentication only). Guarded because the callback contract\n // takes the raw device private key, which is incompatible with a non-exportable, KMS-held key.\n //\n // TODO: implement via a KMS key-agreement operation (ECDH-ES derive-to-secret or KMS-native\n // EMacKey/HMAC) so the key never leaves the KMS — see `keyDeriveEcdhEs` in the askar backend.\n // No new transport needed: the reader ephemeral key is already in the SessionTranscript; the\n // outstanding work is that KMS primitive plus a device-auth mode option on MdocDeviceResponseOptions.\n throw new CredoError(\n 'mdoc device MAC authentication is not supported. Only device signature authentication is currently implemented.'\n )\n },\n hpke: {\n suites: Object.keys(hpkeSuiteToJwaAlgorithm) as HpkeSuiteId[],\n seal: async (input) => {\n const { encrypted, encapsulatedKey } = await kms.encrypt({\n key: {\n keyAgreement: {\n algorithm: jwaAlgorithmForHpkeSuite(input.suite),\n externalPublicJwk: PublicJwk.fromUnknown(input.recipientPublicKey.jwk).toJson() as KmsJwkPublicEcdh,\n info: input.info,\n },\n },\n encryption: { algorithm: 'HPKE', aad: input.aad },\n data: input.plaintext,\n })\n\n if (!encapsulatedKey) {\n throw new CredoError('Key management service did not return an encapsulated key for HPKE seal')\n }\n\n return { enc: encapsulatedKey, ciphertext: encrypted }\n },\n open: async (input) => {\n const { keyId } = input.recipientKey\n if (!keyId) {\n throw new CredoError('Missing required keyId on the recipient key for HPKE open')\n }\n\n const { data } = await kms.decrypt({\n key: {\n keyAgreement: {\n algorithm: jwaAlgorithmForHpkeSuite(input.suite),\n keyId,\n encapsulatedKey: input.enc,\n info: input.info,\n },\n },\n decryption: { algorithm: 'HPKE', aad: input.aad },\n encrypted: input.ciphertext,\n })\n\n return data\n },\n },\n },\n\n cose: {\n mac0: getMac0Context(agentContext),\n sign1: getSign1Context(agentContext),\n },\n\n x509: {\n getSubjectNameField: (input) => {\n const x509Certificate = X509Certificate.fromRawCertificate(input.certificate)\n return x509Certificate.getSubjectNameField(input.field)\n },\n getPublicKey: async (input) => {\n const certificate = X509Certificate.fromRawCertificate(input.certificate)\n return CoseKey.fromJwk(certificate.publicJwk.toJson())\n },\n verifyCertificateChain: async (input) => {\n const certificateChain = input.x5chain.map((cert) => X509Certificate.fromRawCertificate(cert).toString('pem'))\n const trustedCertificates = input.trustedCertificates.map((cert) =>\n X509Certificate.fromRawCertificate(cert).toString('pem')\n ) as [string, ...string[]]\n\n const validatedChain = await X509Service.validateCertificateChain(agentContext, {\n certificateChain,\n trustedCertificates,\n verificationDate: input.now ?? now,\n })\n\n // X509Service.validateCertificateChain returns the chain root-first. The mdoc context contract\n // requires the chain to be leaf-first with the trust anchor (root) as the last entry, so reverse here.\n return {\n chain: validatedChain.map((cert) => cert.rawCertificate).reverse(),\n }\n },\n getCertificateData: async (input) => {\n const { certificate } = input\n const x509Certificate = X509Certificate.fromRawCertificate(certificate)\n return {\n ...x509Certificate.data,\n thumbprint: await x509Certificate.getThumbprintInHex(agentContext),\n }\n },\n },\n } satisfies MdocContext\n}\n"],"mappings":"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"}