ctjs
Version:
CTjs is a full set of classes necessary to work with any kind of Certificate Transparency log (V1 as from RFC6962, or V2 as from RFC6962-bis). In CTjs you could find all necessary validation/verification functions for all related data shipped with full-fe
117 lines (108 loc) • 3.88 kB
JavaScript
import { getParametersValue, fromBase64, stringToArrayBuffer } from "pvutils";
import { SeqStream } from "bytestreamjs";
import DigitallySigned from "./DigitallySigned.js";
import { utils } from "./utils.js";
//**************************************************************************************
export default class SignedTreeHead
{
//**********************************************************************************
/**
* Constructor for SignedTreeHead class
* @param {Object} [parameters={}]
* @property {Object} [schema] asn1js parsed value
*/
constructor(parameters = {})
{
//region Internal properties of the object
/**
* @type {Number}
* @description treeSize
*/
this.treeSize = getParametersValue(parameters, "treeSize", SignedTreeHead.constants("treeSize"));
/**
* @type {Date}
* @description timestamp
*/
this.timestamp = getParametersValue(parameters, "timestamp", SignedTreeHead.constants("timestamp"));
/**
* @type {ArrayBuffer}
* @description rootHash
*/
this.rootHash = getParametersValue(parameters, "rootHash", SignedTreeHead.constants("rootHash"));
/**
* @type {DigitallySigned}
* @description treeHeadSignature
*/
this.treeHeadSignature = getParametersValue(parameters, "treeHeadSignature", SignedTreeHead.constants("treeHeadSignature"));
//endregion
//region If input argument array contains "json" for this object
if("json" in parameters)
this.fromJSON(parameters.json);
//endregion
}
//**********************************************************************************
/**
* Return value for a constant by name
* @param {string} name String name for a constant
*/
static constants(name)
{
switch(name)
{
case "treeSize":
return 0;
case "timestamp":
return (new Date());
case "rootHash":
return (new ArrayBuffer(0));
case "treeHeadSignature":
return (new DigitallySigned());
default:
throw new Error(`Invalid constant name for SignedTreeHead class: ${name}`);
}
}
//**********************************************************************************
/**
* Convert JSON value into current object
* @param {Object} json
* @param {String} json.tree_size
* @param {String} json.timestamp
* @param {String} json.sha256_root_hash
* @param {String} json.tree_head_signature
*/
fromJSON(json)
{
this.treeSize = json.tree_size;
this.timestamp = new Date(json.timestamp);
this.rootHash = stringToArrayBuffer(fromBase64(json.sha256_root_hash));
const stream = new SeqStream({
buffer: stringToArrayBuffer(fromBase64(json.tree_head_signature))
});
this.treeHeadSignature = new DigitallySigned({ stream });
}
//**********************************************************************************
/**
* Verify Signed Tree Head using given public key
* @param {PublicKeyInfo} publicKey Public key using for verification
* @return {Promise<Boolean>}
*/
async verify(publicKey)
{
// digitally-signed struct {
// Version version;
// SignatureType signature_type = tree_hash;
// uint64 timestamp;
// uint64 tree_size;
// opaque sha256_root_hash[32];
// } TreeHeadSignature;
const stream = new SeqStream();
stream.appendChar(0); // version
stream.appendChar(1); // signature_type = tree_hash;
utils.appendUint64(this.timestamp.valueOf(), stream); // timestamp
utils.appendUint64(this.treeSize, stream); // tree_size
stream.appendView(new Uint8Array(this.rootHash)); // sha256_root_hash
return this.treeHeadSignature.verify(stream.buffer, publicKey);
}
//**********************************************************************************
}
//**************************************************************************************