@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
182 lines (181 loc) • 7.71 kB
JavaScript
import { CredoError } from "../../../../error/CredoError.mjs";
import "../../../../error/index.mjs";
import { TypedArrayEncoder } from "../../../../utils/TypedArrayEncoder.mjs";
import { JsonEncoder } from "../../../../utils/JsonEncoder.mjs";
import "../../../../utils/index.mjs";
import { isKnownJwaSignatureAlgorithm } from "../../../kms/jwk/jwa.mjs";
import { PublicJwk } from "../../../kms/jwk/PublicJwk.mjs";
import "../../../kms/index.mjs";
import { suites } from "../adapters/jsonld-signatures-adapter.mjs";
//#region src/modules/vc/linked-data-proofs/signature-suites/JwsLinkedDataSignature.ts
/*!
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
const LinkedDataSignature = suites.LinkedDataSignature;
var JwsLinkedDataSignature = class extends LinkedDataSignature {
/**
* @param options - Options hashmap.
* @param options.type - Provided by subclass.
* @param options.alg - JWS alg provided by subclass.
* @param [options.LDKeyClass] - Provided by subclass or subclass
* overrides `getVerificationMethod`.
*
* Either a `key` OR at least one of `signer`/`verifier` is required.
*
* @param [options.key] - An optional key object (containing an
* `id` property, and either `signer` or `verifier`, depending on the
* intended operation. Useful for when the application is managing keys
* itself (when using a KMS, you never have access to the private key,
* and so should use the `signer` param instead).
*
* Advanced optional parameters and overrides.
*
* @param [options.proof] - A JSON-LD document with options to use
* for the `proof` node. Any other custom fields can be provided here
* using a context different from `security-v2`.
* @param [options.date] - Signing date to use if not passed.
* @param options.contextUrl - JSON-LD context url that corresponds
* to this signature suite. Used for enforcing suite context during the
* `sign()` operation.
* @param [options.useNativeCanonize] - Whether to use a native
* canonize algorithm.
*/
constructor(options) {
super({
type: options.type,
LDKeyClass: options.LDKeyClass,
contextUrl: options.contextUrl,
key: options.key,
signer: void 0,
verifier: void 0,
proof: options.proof,
date: options.date,
useNativeCanonize: options.useNativeCanonize
});
this.alg = options.algorithm;
}
/**
* @param options - Options hashmap.
* @param options.verifyData - The data to sign.
* @param options.proof - A JSON-LD document with options to use
* for the `proof` node. Any other custom fields can be provided here
* using a context different from `security-v2`.
*
* @returns The proof containing the signature value.
*/
async sign(options) {
if (!(this.signer && typeof this.signer.sign === "function")) throw new Error("A signer API has not been specified.");
if (this.key?.publicJwk instanceof PublicJwk) {
if (!isKnownJwaSignatureAlgorithm(this.alg)) throw new CredoError(`Unsupported JWA signature algorithm '${this.alg}' for signature suite ${this.type}`);
this.key.publicJwk.alg = this.alg;
}
const header = {
alg: this.alg,
b64: false,
crit: ["b64"]
};
const encodedHeader = JsonEncoder.toBase64Url(header);
const data = _createJws({
encodedHeader,
verifyData: options.verifyData
});
const signature = await this.signer.sign({ data });
const encodedSignature = TypedArrayEncoder.toBase64Url(signature);
options.proof.jws = `${encodedHeader}..${encodedSignature}`;
return options.proof;
}
/**
* @param options - Options hashmap.
* @param options.verifyData - The data to verify.
* @param options.verificationMethod - A verification method.
* @param options.proof - The proof to be verified.
*
* @returns Resolves with the verification result.
*/
async verifySignature(options) {
if (!(options.proof.jws && typeof options.proof.jws === "string" && options.proof.jws.includes("."))) throw new TypeError("The proof does not include a valid \"jws\" property.");
const [encodedHeader, , encodedSignature] = options.proof.jws.split(".");
let header;
try {
header = JsonEncoder.fromBase64Url(encodedHeader);
} catch (e) {
throw new Error(`Could not parse JWS header; ${e}`);
}
if (!(header && typeof header === "object")) throw new Error("Invalid JWS header.");
if (!(header.alg === this.alg && header.b64 === false && Array.isArray(header.crit) && header.crit.length === 1 && header.crit[0] === "b64" && Object.keys(header).length === 3)) throw new Error(`Invalid JWS header parameters for ${this.type}.`);
const signature = TypedArrayEncoder.fromBase64Url(encodedSignature);
const data = _createJws({
encodedHeader,
verifyData: options.verifyData
});
let { verifier } = this;
if (!verifier) {
const key = await this.LDKeyClass.from(options.verificationMethod);
if (key.publicJwk instanceof PublicJwk) {
if (!isKnownJwaSignatureAlgorithm(header.alg)) throw new CredoError(`Unsupported JWA signature algorithm '${header.alg}' for signature suite ${this.type}`);
key.publicJwk.alg = header.alg;
}
verifier = key.verifier();
}
return verifier.verify({
data,
signature
});
}
async getVerificationMethod(options) {
if (this.key) return this.key.export({ publicKey: true });
let { verificationMethod } = options.proof;
if (typeof verificationMethod === "object" && verificationMethod !== null) verificationMethod = verificationMethod.id;
if (!verificationMethod) throw new Error("No \"verificationMethod\" found in proof.");
if (!options.documentLoader) throw new CredoError("Missing custom document loader. This is required for resolving verification methods.");
const { document } = await options.documentLoader(verificationMethod);
verificationMethod = typeof document === "string" ? JSON.parse(document) : document;
await this.assertVerificationMethod(verificationMethod);
return verificationMethod;
}
/**
* Checks whether a given proof exists in the document.
*
* @param options - Options hashmap.
* @param options.proof - A proof.
* @param options.document - A JSON-LD document.
* @param options.purpose - A jsonld-signatures ProofPurpose
* instance (e.g. AssertionProofPurpose, AuthenticationProofPurpose, etc).
* @param options.documentLoader - A secure document loader (it is
* recommended to use one that provides static known documents, instead of
* fetching from the web) for returning contexts, controller documents,
* keys, and other relevant URLs needed for the proof.
*
* @returns Whether a match for the proof was found.
*/
async matchProof(options) {
if (!await super.matchProof({
proof: options.proof,
document: options.document,
purpose: options.purpose,
documentLoader: options.documentLoader
})) return false;
if (!this.key) return true;
const { verificationMethod } = options.proof;
if (typeof verificationMethod === "object") return verificationMethod.id === this.key.id;
return verificationMethod === this.key.id;
}
};
/**
* Creates the bytes ready for signing.
*
* @param {object} options - Options hashmap.
* @param {string} options.encodedHeader - A base64url encoded JWT header.
* @param {Uint8Array} options.verifyData - Payload to sign/verify.
* @returns {Uint8Array} A combined byte array for signing.
*/
function _createJws(options) {
const encodedHeaderBytes = TypedArrayEncoder.fromUtf8String(`${options.encodedHeader}.`);
const data = new Uint8Array(encodedHeaderBytes.length + options.verifyData.length);
data.set(encodedHeaderBytes, 0);
data.set(options.verifyData, encodedHeaderBytes.length);
return data;
}
//#endregion
export { JwsLinkedDataSignature };
//# sourceMappingURL=JwsLinkedDataSignature.mjs.map