@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 • 15.9 kB
Source Map (JSON)
{"version":3,"file":"PublicJwk.mjs","names":[],"sources":["../../../../src/modules/kms/jwk/PublicJwk.ts"],"sourcesContent":["import type { HashName } from '../../../crypto'\nimport { CredoError } from '../../../error'\nimport { MultiBaseEncoder, TypedArrayEncoder, VarintEncoder } from '../../../utils'\nimport type { Constructor } from '../../../utils/mixins'\nimport { zParseWithErrorHandling } from '../../../utils/zod'\nimport { KeyManagementError } from '../error/KeyManagementError'\nimport { legacyKeyIdFromPublicJwk } from '../legacy'\nimport { asymmetricPublicJwkMatches } from './equals'\nimport { getJwkHumanDescription } from './humanDescription'\nimport type { KnownJwaKeyAgreementAlgorithm, KnownJwaSignatureAlgorithm } from './jwa'\nimport { calculateJwkThumbprint } from './jwkThumbprint'\nimport { assertJwkAsymmetric, type KmsJwkPublicAsymmetric, publicJwkFromPrivateJwk, zKmsJwkPublic } from './knownJwk'\nimport {\n Ed25519PublicJwk,\n P256PublicJwk,\n P384PublicJwk,\n P521PublicJwk,\n RsaPublicJwk,\n Secp256k1PublicJwk,\n X25519PublicJwk,\n} from './kty'\n\nexport const SupportedPublicJwks = [\n Ed25519PublicJwk,\n P256PublicJwk,\n P384PublicJwk,\n P521PublicJwk,\n RsaPublicJwk,\n Secp256k1PublicJwk,\n X25519PublicJwk,\n]\nexport type SupportedPublicJwkClass = (typeof SupportedPublicJwks)[number]\nexport type SupportedPublicJwk =\n | Ed25519PublicJwk\n | P256PublicJwk\n | P384PublicJwk\n | P521PublicJwk\n | RsaPublicJwk\n | Secp256k1PublicJwk\n | X25519PublicJwk\n\ntype ExtractByJwk<T, K> = T extends { jwk: infer J } ? (K extends J ? T : never) : never\n\ntype ExtractByPublicKey<T, K> = T extends { publicKey: infer J } ? (K extends J ? T : never) : never\n\nexport class PublicJwk<Jwk extends SupportedPublicJwk = SupportedPublicJwk> {\n private constructor(private readonly jwk: Jwk) {}\n\n public static fromUnknown(jwkJson: unknown) {\n // We remove any private properties if they are present\n const publicJwk = publicJwkFromPrivateJwk(zParseWithErrorHandling(zKmsJwkPublic, jwkJson, 'jwk is not a valid jwk'))\n assertJwkAsymmetric(publicJwk)\n\n let jwkInstance: SupportedPublicJwk\n if (publicJwk.kty === 'RSA') {\n jwkInstance = new RsaPublicJwk(publicJwk)\n } else if (publicJwk.kty === 'EC') {\n if (publicJwk.crv === 'P-256') {\n jwkInstance = new P256PublicJwk({\n ...publicJwk,\n crv: publicJwk.crv,\n })\n } else if (publicJwk.crv === 'P-384') {\n jwkInstance = new P384PublicJwk({\n ...publicJwk,\n crv: publicJwk.crv,\n })\n } else if (publicJwk.crv === 'P-521') {\n jwkInstance = new P521PublicJwk({\n ...publicJwk,\n crv: publicJwk.crv,\n })\n } else if (publicJwk.crv === 'secp256k1') {\n jwkInstance = new Secp256k1PublicJwk({\n ...publicJwk,\n crv: publicJwk.crv,\n })\n } else {\n throw new KeyManagementError(\n `Unsupported kty '${publicJwk.kty}' with crv '${publicJwk.crv}' for creating jwk instance`\n )\n }\n } else if (publicJwk.crv === 'Ed25519') {\n jwkInstance = new Ed25519PublicJwk({\n ...publicJwk,\n crv: publicJwk.crv,\n })\n } else if (publicJwk.crv === 'X25519') {\n jwkInstance = new X25519PublicJwk({\n ...publicJwk,\n crv: publicJwk.crv,\n })\n } else {\n throw new KeyManagementError(`Unsupported kty '${publicJwk.kty}' for creating jwk instance`)\n }\n\n return new PublicJwk(jwkInstance)\n }\n\n // FIXME: all Jwk combinations should be separate types.\n // so not kty: EC, and crv: P-256 | P-384\n // but: kty: EC, and crv: P-256 | kty: EC, and crv: P-384\n // As the first approach messes with TypeScript's type inference\n public static fromPublicJwk<Jwk extends KmsJwkPublicAsymmetric>(jwk: Jwk) {\n return PublicJwk.fromUnknown(jwk) as PublicJwk<\n ExtractByJwk<SupportedPublicJwk, Jwk> extends never ? SupportedPublicJwk : ExtractByJwk<SupportedPublicJwk, Jwk>\n >\n }\n\n public toJson({ includeKid = true }: { includeKid?: boolean } = {}): Jwk['jwk'] {\n if (includeKid) return this.jwk.jwk\n\n const { kid, ...jwk } = this.jwk.jwk\n return jwk\n }\n\n /**\n * Get the signature algorithms supported for this jwk.\n *\n * If the jwk has an `alg` field defined it will only return that alg\n * and otherwise return all known supported signature algorithms.\n */\n public get supportedSignatureAlgorithms(): KnownJwaSignatureAlgorithm[] {\n const supportedSignatureAlgorithms: KnownJwaSignatureAlgorithm[] = this.jwk.supportedSignatureAlgorithms ?? []\n\n if (this.jwk.jwk.alg) {\n if (!supportedSignatureAlgorithms.includes(this.jwk.jwk.alg as KnownJwaSignatureAlgorithm)) {\n throw new KeyManagementError(\n `${this.jwkTypeHumanDescription} defines alg '${this.jwk.jwk.alg}' but this alg is not supported.`\n )\n }\n\n return [this.jwk.jwk.alg] as this['supportedSignatureAlgorithms']\n }\n\n return supportedSignatureAlgorithms\n }\n\n public get supportedEncryptionKeyAgreementAlgorithms(): KnownJwaKeyAgreementAlgorithm[] {\n return this.jwk.supportedEncryptionKeyAgreementAlgorithms ?? []\n }\n\n /**\n * key type as defined in [JWA Specification](https://tools.ietf.org/html/rfc7518#section-6.1)\n */\n public get kty(): Jwk['jwk']['kty'] {\n return this.jwk.jwk.kty\n }\n\n /**\n * Get the key id for a public jwk. If the public jwk does not have\n * a key id, an error will be thrown\n */\n public get keyId(): string {\n if (this.jwk.jwk.kid) return this.jwk.jwk.kid\n\n throw new KeyManagementError('Unable to determine keyId for jwk')\n }\n\n public get hasKeyId(): boolean {\n return this.jwk.jwk.kid !== undefined\n }\n\n public set keyId(keyId: string) {\n this.jwk.jwk.kid = keyId\n }\n\n public get legacyKeyId() {\n return legacyKeyIdFromPublicJwk(this)\n }\n\n public get publicKey(): Jwk['publicKey'] {\n return this.jwk.publicKey\n }\n\n /**\n * Return the compressed public key. If the key type does not support compressed public keys, it will return null\n */\n public get compressedPublicKey(): Jwk['compressedPublicKey'] {\n return this.jwk.compressedPublicKey\n }\n\n public get JwkClass() {\n return this.jwk.constructor as SupportedPublicJwkClass\n }\n\n /**\n * SHA-256 jwk thumbprint\n */\n public getJwkThumbprint(hashAlgorithm: HashName = 'sha-256') {\n return calculateJwkThumbprint({\n jwk: this.jwk.jwk,\n hashAlgorithm: hashAlgorithm,\n })\n }\n\n /**\n * Get the first signature algorithm to use with this jwk. If the jwk has an `alg` field defined\n * it will use that alg, and otherwise fall back to the first supported signature algorithm.\n *\n * If no algorithm is supported it will throw an error\n */\n public get signatureAlgorithm() {\n const alg = this.supportedSignatureAlgorithms[0]\n if (!alg) {\n throw new KeyManagementError(`${this.jwkTypeHumanDescription} has no supported signature algorithms`)\n }\n\n return alg as this['supportedSignatureAlgorithms'][number]\n }\n\n public assertSignatureAlgorithmSupported(\n alg: KnownJwaSignatureAlgorithm\n ): asserts alg is this['supportedSignatureAlgorithms'][number] {\n if (!this.supportedSignatureAlgorithms.includes(alg)) {\n throw new KeyManagementError(`${this.jwkTypeHumanDescription} does not support signature alg '${alg}'.`)\n }\n }\n\n public static fromPublicKey<Supported extends SupportedPublicJwk['publicKey']>(publicKey: Supported) {\n let jwkInstance: SupportedPublicJwk\n\n if (publicKey.kty === 'RSA') {\n jwkInstance = RsaPublicJwk.fromPublicKey(publicKey)\n } else if (publicKey.kty === 'EC') {\n if (publicKey.crv === 'P-256') {\n jwkInstance = P256PublicJwk.fromPublicKey(publicKey.publicKey)\n } else if (publicKey.crv === 'P-384') {\n jwkInstance = P384PublicJwk.fromPublicKey(publicKey.publicKey)\n } else if (publicKey.crv === 'P-521') {\n jwkInstance = P521PublicJwk.fromPublicKey(publicKey.publicKey)\n } else if (publicKey.crv === 'secp256k1') {\n jwkInstance = Secp256k1PublicJwk.fromPublicKey(publicKey.publicKey)\n } else {\n throw new KeyManagementError(\n // @ts-expect-error\n `Unsupported kty '${publicKey.kty}' with crv '${publicKey.crv}' for creating jwk instance based on public key bytes`\n )\n }\n } else if (publicKey.crv === 'X25519') {\n jwkInstance = X25519PublicJwk.fromPublicKey(publicKey.publicKey)\n } else if (publicKey.crv === 'Ed25519') {\n jwkInstance = Ed25519PublicJwk.fromPublicKey(publicKey.publicKey)\n } else {\n throw new KeyManagementError(\n // @ts-expect-error\n `Unsupported kty '${publicKey.kty}' for creating jwk instance based on public key bytes`\n )\n }\n\n return new PublicJwk(jwkInstance) as PublicJwk<ExtractByPublicKey<SupportedPublicJwk, Supported>>\n }\n\n /**\n * Returns the jwk encoded a Base58 multibase encoded multicodec key\n */\n public get fingerprint() {\n const prefixBytes = VarintEncoder.encode(this.jwk.multicodecPrefix)\n const prefixedPublicKey = new Uint8Array([...prefixBytes, ...this.jwk.multicodec])\n\n return `z${TypedArrayEncoder.toBase58(prefixedPublicKey)}`\n }\n\n /**\n * Create a jwk instance based on a Base58 multibase encoded multicodec key\n */\n public static fromFingerprint(fingerprint: string) {\n const { data } = MultiBaseEncoder.decode(fingerprint)\n const [code, byteLength] = VarintEncoder.decode(data)\n const publicKey = data.slice(byteLength)\n\n const PublicJwkClass = SupportedPublicJwks.find((JwkClass) => JwkClass.multicodecPrefix === code)\n if (!PublicJwkClass) {\n throw new KeyManagementError(`Unsupported multicodec public key with prefix '${code}'`)\n }\n\n const jwk = PublicJwkClass.fromMulticodec(publicKey)\n return new PublicJwk(jwk)\n }\n\n /**\n * Check whether this PublicJwk instance is of a specific type\n */\n public is<\n Jwk1 extends SupportedPublicJwk,\n Jwk2 extends SupportedPublicJwk = Jwk1,\n Jwk3 extends SupportedPublicJwk = Jwk1,\n >(\n jwkType1: Constructor<Jwk1>,\n jwkType2?: Constructor<Jwk2>,\n jwkType3?: Constructor<Jwk3>\n ): this is PublicJwk<Jwk1> | PublicJwk<Jwk2> | PublicJwk<Jwk3> {\n const types = [jwkType1, jwkType2, jwkType3].filter(Boolean) as Constructor<SupportedPublicJwk>[]\n return types.some((type) => this.jwk.constructor === type)\n }\n\n /**\n * Convert the PublicJwk to another type.\n *\n * NOTE: only supported for Ed25519 to X25519 at the moment\n */\n public convertTo(\n type: Jwk extends Ed25519PublicJwk ? typeof X25519PublicJwk : never\n ): Jwk extends Ed25519PublicJwk ? PublicJwk<X25519PublicJwk> : never {\n if (!this.is(Ed25519PublicJwk) || type !== X25519PublicJwk) {\n throw new KeyManagementError('Unsupported key conversion. Only Ed25519 to X25519 is supported.')\n }\n\n return PublicJwk.fromPublicJwk(this.jwk.toX25519PublicJwk()) as Jwk extends Ed25519PublicJwk\n ? PublicJwk<X25519PublicJwk>\n : never\n }\n\n /**\n * Check whether this jwk instance is the same as another jwk instance.\n * It does this by comparing the key types and public keys, not other fields\n * of the JWK such as keyId, use, etc..\n */\n public equals(other: PublicJwk) {\n return asymmetricPublicJwkMatches(this.toJson(), other.toJson())\n }\n\n /**\n * Get human description of a jwk type. This does\n * not include the (public) key material\n */\n public get jwkTypeHumanDescription() {\n return getJwkHumanDescription(this.toJson())\n }\n\n public static supportedPublicJwkClassForSignatureAlgorithm(alg: KnownJwaSignatureAlgorithm): SupportedPublicJwkClass {\n const supportedPublicJwkClass = SupportedPublicJwks.find((JwkClass) =>\n JwkClass.supportedSignatureAlgorithms.includes(alg)\n )\n\n if (!supportedPublicJwkClass) {\n throw new CredoError(`Could not determine supported public jwk class for alg '${alg}'`)\n }\n\n return supportedPublicJwkClass\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,sBAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAeD,IAAa,YAAb,MAAa,UAA+D;CAC1E,AAAQ,YAAY,AAAiB,KAAU;EAAV;;CAErC,OAAc,YAAY,SAAkB;EAE1C,MAAM,YAAY,wBAAwB,wBAAwB,eAAe,SAAS,yBAAyB,CAAC;AACpH,sBAAoB,UAAU;EAE9B,IAAI;AACJ,MAAI,UAAU,QAAQ,MACpB,eAAc,IAAI,aAAa,UAAU;WAChC,UAAU,QAAQ,KAC3B,KAAI,UAAU,QAAQ,QACpB,eAAc,IAAI,cAAc;GAC9B,GAAG;GACH,KAAK,UAAU;GAChB,CAAC;WACO,UAAU,QAAQ,QAC3B,eAAc,IAAI,cAAc;GAC9B,GAAG;GACH,KAAK,UAAU;GAChB,CAAC;WACO,UAAU,QAAQ,QAC3B,eAAc,IAAI,cAAc;GAC9B,GAAG;GACH,KAAK,UAAU;GAChB,CAAC;WACO,UAAU,QAAQ,YAC3B,eAAc,IAAI,mBAAmB;GACnC,GAAG;GACH,KAAK,UAAU;GAChB,CAAC;MAEF,OAAM,IAAI,mBACR,oBAAoB,UAAU,IAAI,cAAc,UAAU,IAAI,6BAC/D;WAEM,UAAU,QAAQ,UAC3B,eAAc,IAAI,iBAAiB;GACjC,GAAG;GACH,KAAK,UAAU;GAChB,CAAC;WACO,UAAU,QAAQ,SAC3B,eAAc,IAAI,gBAAgB;GAChC,GAAG;GACH,KAAK,UAAU;GAChB,CAAC;MAEF,OAAM,IAAI,mBAAmB,oBAAoB,UAAU,IAAI,6BAA6B;AAG9F,SAAO,IAAI,UAAU,YAAY;;CAOnC,OAAc,cAAkD,KAAU;AACxE,SAAO,UAAU,YAAY,IAAI;;CAKnC,AAAO,OAAO,EAAE,aAAa,SAAmC,EAAE,EAAc;AAC9E,MAAI,WAAY,QAAO,KAAK,IAAI;EAEhC,MAAM,EAAE,KAAK,GAAG,QAAQ,KAAK,IAAI;AACjC,SAAO;;;;;;;;CAST,IAAW,+BAA6D;EACtE,MAAM,+BAA6D,KAAK,IAAI,gCAAgC,EAAE;AAE9G,MAAI,KAAK,IAAI,IAAI,KAAK;AACpB,OAAI,CAAC,6BAA6B,SAAS,KAAK,IAAI,IAAI,IAAkC,CACxF,OAAM,IAAI,mBACR,GAAG,KAAK,wBAAwB,gBAAgB,KAAK,IAAI,IAAI,IAAI,kCAClE;AAGH,UAAO,CAAC,KAAK,IAAI,IAAI,IAAI;;AAG3B,SAAO;;CAGT,IAAW,4CAA6E;AACtF,SAAO,KAAK,IAAI,6CAA6C,EAAE;;;;;CAMjE,IAAW,MAAyB;AAClC,SAAO,KAAK,IAAI,IAAI;;;;;;CAOtB,IAAW,QAAgB;AACzB,MAAI,KAAK,IAAI,IAAI,IAAK,QAAO,KAAK,IAAI,IAAI;AAE1C,QAAM,IAAI,mBAAmB,oCAAoC;;CAGnE,IAAW,WAAoB;AAC7B,SAAO,KAAK,IAAI,IAAI,QAAQ;;CAG9B,IAAW,MAAM,OAAe;AAC9B,OAAK,IAAI,IAAI,MAAM;;CAGrB,IAAW,cAAc;AACvB,SAAO,yBAAyB,KAAK;;CAGvC,IAAW,YAA8B;AACvC,SAAO,KAAK,IAAI;;;;;CAMlB,IAAW,sBAAkD;AAC3D,SAAO,KAAK,IAAI;;CAGlB,IAAW,WAAW;AACpB,SAAO,KAAK,IAAI;;;;;CAMlB,AAAO,iBAAiB,gBAA0B,WAAW;AAC3D,SAAO,uBAAuB;GAC5B,KAAK,KAAK,IAAI;GACC;GAChB,CAAC;;;;;;;;CASJ,IAAW,qBAAqB;EAC9B,MAAM,MAAM,KAAK,6BAA6B;AAC9C,MAAI,CAAC,IACH,OAAM,IAAI,mBAAmB,GAAG,KAAK,wBAAwB,wCAAwC;AAGvG,SAAO;;CAGT,AAAO,kCACL,KAC6D;AAC7D,MAAI,CAAC,KAAK,6BAA6B,SAAS,IAAI,CAClD,OAAM,IAAI,mBAAmB,GAAG,KAAK,wBAAwB,mCAAmC,IAAI,IAAI;;CAI5G,OAAc,cAAiE,WAAsB;EACnG,IAAI;AAEJ,MAAI,UAAU,QAAQ,MACpB,eAAc,aAAa,cAAc,UAAU;WAC1C,UAAU,QAAQ,KAC3B,KAAI,UAAU,QAAQ,QACpB,eAAc,cAAc,cAAc,UAAU,UAAU;WACrD,UAAU,QAAQ,QAC3B,eAAc,cAAc,cAAc,UAAU,UAAU;WACrD,UAAU,QAAQ,QAC3B,eAAc,cAAc,cAAc,UAAU,UAAU;WACrD,UAAU,QAAQ,YAC3B,eAAc,mBAAmB,cAAc,UAAU,UAAU;MAEnE,OAAM,IAAI,mBAER,oBAAoB,UAAU,IAAI,cAAc,UAAU,IAAI,uDAC/D;WAEM,UAAU,QAAQ,SAC3B,eAAc,gBAAgB,cAAc,UAAU,UAAU;WACvD,UAAU,QAAQ,UAC3B,eAAc,iBAAiB,cAAc,UAAU,UAAU;MAEjE,OAAM,IAAI,mBAER,oBAAoB,UAAU,IAAI,uDACnC;AAGH,SAAO,IAAI,UAAU,YAAY;;;;;CAMnC,IAAW,cAAc;EACvB,MAAM,cAAc,cAAc,OAAO,KAAK,IAAI,iBAAiB;EACnE,MAAM,oBAAoB,IAAI,WAAW,CAAC,GAAG,aAAa,GAAG,KAAK,IAAI,WAAW,CAAC;AAElF,SAAO,IAAI,kBAAkB,SAAS,kBAAkB;;;;;CAM1D,OAAc,gBAAgB,aAAqB;EACjD,MAAM,EAAE,SAAS,iBAAiB,OAAO,YAAY;EACrD,MAAM,CAAC,MAAM,cAAc,cAAc,OAAO,KAAK;EACrD,MAAM,YAAY,KAAK,MAAM,WAAW;EAExC,MAAM,iBAAiB,oBAAoB,MAAM,aAAa,SAAS,qBAAqB,KAAK;AACjG,MAAI,CAAC,eACH,OAAM,IAAI,mBAAmB,kDAAkD,KAAK,GAAG;AAIzF,SAAO,IAAI,UADC,eAAe,eAAe,UAAU,CAC3B;;;;;CAM3B,AAAO,GAKL,UACA,UACA,UAC6D;AAE7D,SADc;GAAC;GAAU;GAAU;GAAS,CAAC,OAAO,QAAQ,CAC/C,MAAM,SAAS,KAAK,IAAI,gBAAgB,KAAK;;;;;;;CAQ5D,AAAO,UACL,MACmE;AACnE,MAAI,CAAC,KAAK,GAAG,iBAAiB,IAAI,SAAS,gBACzC,OAAM,IAAI,mBAAmB,mEAAmE;AAGlG,SAAO,UAAU,cAAc,KAAK,IAAI,mBAAmB,CAAC;;;;;;;CAU9D,AAAO,OAAO,OAAkB;AAC9B,SAAO,2BAA2B,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;;;;;;CAOlE,IAAW,0BAA0B;AACnC,SAAO,uBAAuB,KAAK,QAAQ,CAAC;;CAG9C,OAAc,6CAA6C,KAA0D;EACnH,MAAM,0BAA0B,oBAAoB,MAAM,aACxD,SAAS,6BAA6B,SAAS,IAAI,CACpD;AAED,MAAI,CAAC,wBACH,OAAM,IAAI,WAAW,2DAA2D,IAAI,GAAG;AAGzF,SAAO"}