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

230 lines (226 loc) • 8.99 kB
import { CredoError } from "../../../error/CredoError.mjs"; import "../../../error/index.mjs"; import { TypedArrayEncoder } from "../../../utils/TypedArrayEncoder.mjs"; import { MultiBaseEncoder } from "../../../utils/MultiBaseEncoder.mjs"; import { VarintEncoder } from "../../../utils/VarintEncoder.mjs"; import "../../../utils/index.mjs"; import { KeyManagementError } from "../error/KeyManagementError.mjs"; import { getJwkHumanDescription } from "./humanDescription.mjs"; import { asymmetricPublicJwkMatches } from "./equals.mjs"; import { zParseWithErrorHandling } from "../../../utils/zod.mjs"; import { assertJwkAsymmetric, publicJwkFromPrivateJwk, zKmsJwkPublic } from "./knownJwk.mjs"; import { P256PublicJwk } from "./kty/ec/P256PublicJwk.mjs"; import { P384PublicJwk } from "./kty/ec/P384PublicJwk.mjs"; import { P521PublicJwk } from "./kty/ec/P521PublicJwk.mjs"; import { Secp256k1PublicJwk } from "./kty/ec/Secp256k1PublicJwk.mjs"; import { X25519PublicJwk } from "./kty/okp/X25519PublicJwk.mjs"; import { Ed25519PublicJwk } from "./kty/okp/Ed25519PublicJwk.mjs"; import { RsaPublicJwk } from "./kty/rsa/RsaPublicJwk.mjs"; import "./kty/index.mjs"; import { legacyKeyIdFromPublicJwk } from "../legacy.mjs"; import { calculateJwkThumbprint } from "./jwkThumbprint.mjs"; //#region src/modules/kms/jwk/PublicJwk.ts const SupportedPublicJwks = [ Ed25519PublicJwk, P256PublicJwk, P384PublicJwk, P521PublicJwk, RsaPublicJwk, Secp256k1PublicJwk, X25519PublicJwk ]; var PublicJwk = class PublicJwk { constructor(jwk) { this.jwk = jwk; } static fromUnknown(jwkJson) { const publicJwk = publicJwkFromPrivateJwk(zParseWithErrorHandling(zKmsJwkPublic, jwkJson, "jwk is not a valid jwk")); assertJwkAsymmetric(publicJwk); let jwkInstance; if (publicJwk.kty === "RSA") jwkInstance = new RsaPublicJwk(publicJwk); else if (publicJwk.kty === "EC") if (publicJwk.crv === "P-256") jwkInstance = new P256PublicJwk({ ...publicJwk, crv: publicJwk.crv }); else if (publicJwk.crv === "P-384") jwkInstance = new P384PublicJwk({ ...publicJwk, crv: publicJwk.crv }); else if (publicJwk.crv === "P-521") jwkInstance = new P521PublicJwk({ ...publicJwk, crv: publicJwk.crv }); else if (publicJwk.crv === "secp256k1") jwkInstance = new Secp256k1PublicJwk({ ...publicJwk, crv: publicJwk.crv }); else throw new KeyManagementError(`Unsupported kty '${publicJwk.kty}' with crv '${publicJwk.crv}' for creating jwk instance`); else if (publicJwk.crv === "Ed25519") jwkInstance = new Ed25519PublicJwk({ ...publicJwk, crv: publicJwk.crv }); else if (publicJwk.crv === "X25519") jwkInstance = new X25519PublicJwk({ ...publicJwk, crv: publicJwk.crv }); else throw new KeyManagementError(`Unsupported kty '${publicJwk.kty}' for creating jwk instance`); return new PublicJwk(jwkInstance); } static fromPublicJwk(jwk) { return PublicJwk.fromUnknown(jwk); } toJson({ includeKid = true } = {}) { if (includeKid) return this.jwk.jwk; const { kid, ...jwk } = this.jwk.jwk; return jwk; } /** * Get the signature algorithms supported for this jwk. * * If the jwk has an `alg` field defined it will only return that alg * and otherwise return all known supported signature algorithms. */ get supportedSignatureAlgorithms() { const supportedSignatureAlgorithms = this.jwk.supportedSignatureAlgorithms ?? []; if (this.jwk.jwk.alg) { if (!supportedSignatureAlgorithms.includes(this.jwk.jwk.alg)) throw new KeyManagementError(`${this.jwkTypeHumanDescription} defines alg '${this.jwk.jwk.alg}' but this alg is not supported.`); return [this.jwk.jwk.alg]; } return supportedSignatureAlgorithms; } get supportedEncryptionKeyAgreementAlgorithms() { return this.jwk.supportedEncryptionKeyAgreementAlgorithms ?? []; } /** * key type as defined in [JWA Specification](https://tools.ietf.org/html/rfc7518#section-6.1) */ get kty() { return this.jwk.jwk.kty; } /** * Get the key id for a public jwk. If the public jwk does not have * a key id, an error will be thrown */ get keyId() { if (this.jwk.jwk.kid) return this.jwk.jwk.kid; throw new KeyManagementError("Unable to determine keyId for jwk"); } get hasKeyId() { return this.jwk.jwk.kid !== void 0; } set keyId(keyId) { this.jwk.jwk.kid = keyId; } get legacyKeyId() { return legacyKeyIdFromPublicJwk(this); } get publicKey() { return this.jwk.publicKey; } /** * Return the compressed public key. If the key type does not support compressed public keys, it will return null */ get compressedPublicKey() { return this.jwk.compressedPublicKey; } get JwkClass() { return this.jwk.constructor; } /** * SHA-256 jwk thumbprint */ getJwkThumbprint(hashAlgorithm = "sha-256") { return calculateJwkThumbprint({ jwk: this.jwk.jwk, hashAlgorithm }); } /** * Get the first signature algorithm to use with this jwk. If the jwk has an `alg` field defined * it will use that alg, and otherwise fall back to the first supported signature algorithm. * * If no algorithm is supported it will throw an error */ get signatureAlgorithm() { const alg = this.supportedSignatureAlgorithms[0]; if (!alg) throw new KeyManagementError(`${this.jwkTypeHumanDescription} has no supported signature algorithms`); return alg; } assertSignatureAlgorithmSupported(alg) { if (!this.supportedSignatureAlgorithms.includes(alg)) throw new KeyManagementError(`${this.jwkTypeHumanDescription} does not support signature alg '${alg}'.`); } static fromPublicKey(publicKey) { let jwkInstance; if (publicKey.kty === "RSA") jwkInstance = RsaPublicJwk.fromPublicKey(publicKey); else if (publicKey.kty === "EC") if (publicKey.crv === "P-256") jwkInstance = P256PublicJwk.fromPublicKey(publicKey.publicKey); else if (publicKey.crv === "P-384") jwkInstance = P384PublicJwk.fromPublicKey(publicKey.publicKey); else if (publicKey.crv === "P-521") jwkInstance = P521PublicJwk.fromPublicKey(publicKey.publicKey); else if (publicKey.crv === "secp256k1") jwkInstance = Secp256k1PublicJwk.fromPublicKey(publicKey.publicKey); else throw new KeyManagementError(`Unsupported kty '${publicKey.kty}' with crv '${publicKey.crv}' for creating jwk instance based on public key bytes`); else if (publicKey.crv === "X25519") jwkInstance = X25519PublicJwk.fromPublicKey(publicKey.publicKey); else if (publicKey.crv === "Ed25519") jwkInstance = Ed25519PublicJwk.fromPublicKey(publicKey.publicKey); else throw new KeyManagementError(`Unsupported kty '${publicKey.kty}' for creating jwk instance based on public key bytes`); return new PublicJwk(jwkInstance); } /** * Returns the jwk encoded a Base58 multibase encoded multicodec key */ get fingerprint() { const prefixBytes = VarintEncoder.encode(this.jwk.multicodecPrefix); const prefixedPublicKey = new Uint8Array([...prefixBytes, ...this.jwk.multicodec]); return `z${TypedArrayEncoder.toBase58(prefixedPublicKey)}`; } /** * Create a jwk instance based on a Base58 multibase encoded multicodec key */ static fromFingerprint(fingerprint) { const { data } = MultiBaseEncoder.decode(fingerprint); const [code, byteLength] = VarintEncoder.decode(data); const publicKey = data.slice(byteLength); const PublicJwkClass = SupportedPublicJwks.find((JwkClass) => JwkClass.multicodecPrefix === code); if (!PublicJwkClass) throw new KeyManagementError(`Unsupported multicodec public key with prefix '${code}'`); return new PublicJwk(PublicJwkClass.fromMulticodec(publicKey)); } /** * Check whether this PublicJwk instance is of a specific type */ is(jwkType1, jwkType2, jwkType3) { return [ jwkType1, jwkType2, jwkType3 ].filter(Boolean).some((type) => this.jwk.constructor === type); } /** * Convert the PublicJwk to another type. * * NOTE: only supported for Ed25519 to X25519 at the moment */ convertTo(type) { if (!this.is(Ed25519PublicJwk) || type !== X25519PublicJwk) throw new KeyManagementError("Unsupported key conversion. Only Ed25519 to X25519 is supported."); return PublicJwk.fromPublicJwk(this.jwk.toX25519PublicJwk()); } /** * Check whether this jwk instance is the same as another jwk instance. * It does this by comparing the key types and public keys, not other fields * of the JWK such as keyId, use, etc.. */ equals(other) { return asymmetricPublicJwkMatches(this.toJson(), other.toJson()); } /** * Get human description of a jwk type. This does * not include the (public) key material */ get jwkTypeHumanDescription() { return getJwkHumanDescription(this.toJson()); } static supportedPublicJwkClassForSignatureAlgorithm(alg) { const supportedPublicJwkClass = SupportedPublicJwks.find((JwkClass) => JwkClass.supportedSignatureAlgorithms.includes(alg)); if (!supportedPublicJwkClass) throw new CredoError(`Could not determine supported public jwk class for alg '${alg}'`); return supportedPublicJwkClass; } }; //#endregion export { PublicJwk }; //# sourceMappingURL=PublicJwk.mjs.map