@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
247 lines (246 loc) • 9.78 kB
JavaScript
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;
}
/**
* The `alg` field of the jwk, indicating the algorithm the key is intended to be used with.
*/
get alg() {
return this.jwk.jwk.alg;
}
/**
* Set the `alg` field of the jwk, indicating the algorithm the key is intended to be used
* with. This restricts the jwk to that algorithm (e.g. {@link signatureAlgorithm} will
* return the `alg` when defined).
*
* If the algorithm is not supported by this jwk an error will be thrown.
*/
set alg(alg) {
if (![...this.jwk.supportedSignatureAlgorithms ?? [], ...this.jwk.supportedEncryptionKeyAgreementAlgorithms ?? []].includes(alg)) throw new KeyManagementError(`${this.jwkTypeHumanDescription} does not support alg '${alg}'.`);
this.jwk.jwk.alg = 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}'`);
const jwk = PublicJwkClass.fromMulticodec(publicKey);
return new PublicJwk(jwk);
}
/**
* 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, SupportedPublicJwks };
//# sourceMappingURL=PublicJwk.mjs.map