cadesjs
Version:
CAdESjs gives you an ability to make CAdES signatures on pure JavaScript. The libray made with latest CAdES standards in mind
149 lines (131 loc) • 5.13 kB
JavaScript
import * as asn1js from "asn1js";
import { getParametersValue, utilConcatBuf } from "pvutils";
import {
getCrypto,
ContentInfo,
Attribute,
TimeStampResp
} from "pkijs";
//**************************************************************************************
// noinspection JSUnusedGlobalSymbols
export default class CAdESCTimestamp extends ContentInfo
{
//**********************************************************************************
/**
* Constructor for CAdESCTimestamp class
* @param {Object} [parameters={}]
* @property {Object} [schema] asn1js parsed value
*/
constructor(parameters = {})
{
super(parameters);
/**
* @type {ArrayBuffer}
* @description tspResponse
*/
this.tspResponse = getParametersValue(parameters, "tspResponse", new ArrayBuffer(0));
}
//**********************************************************************************
// noinspection JSUnusedGlobalSymbols
/**
* Get "ArrayBuffer" to transfer to time-stamp server
* @param {SignedData} cmsSignedData CMS Signed Data to make attribute for
* @param {number} signerIndex Index of signer to make attribute for
* @param {Object} [parameters] Additional parameters for making attribute
* @returns {Promise}
*/
getStampingBuffer(cmsSignedData, signerIndex, parameters = {})
{
//region Initial variables
let sequence = Promise.resolve();
let hashAlgorithm = "SHA-256";
let resultBuffer = new ArrayBuffer(0);
let signatureTimeStamp; // SignatureTimeStamp
let completeCertificateReferences; // CompleteCertificateReferences
let completeRevocationReferences; // CompleteRevocationReferences
//endregion
//region Get a "crypto" extension
const crypto = getCrypto();
if(typeof crypto === "undefined")
return Promise.reject("Unable to create WebCrypto object");
//endregion
//region Check input parameters
if("hashAlgorithm" in parameters)
hashAlgorithm = parameters.hashAlgorithm;
if("signatureTimeStamp" in parameters)
signatureTimeStamp = parameters.signatureTimeStamp;
else
return Promise.reject("Parameter \"signatureTimeStamp\" is mandatory for making \"CAdES-C-Timestamp\" attribute");
if("completeCertificateReferences" in parameters)
completeCertificateReferences = parameters.completeCertificateReferences;
else
return Promise.reject("Parameter \"completeCertificateReferences\" is mandatory for making \"CAdES-C-Timestamp\" attribute");
if("completeRevocationReferences" in parameters)
completeRevocationReferences = parameters.completeRevocationReferences;
else
return Promise.reject("Parameter \"completeRevocationReferences\" is mandatory for making \"CAdES-C-Timestamp\" attribute");
//endregion
//region Make stamping buffer
sequence = sequence.then(
() => {
resultBuffer = utilConcatBuf(resultBuffer, cmsSignedData.signerInfos[signerIndex].signature.valueBlock.valueHex);
resultBuffer = utilConcatBuf(resultBuffer, signatureTimeStamp.makeAttribute().toSchema().toBER(false));
resultBuffer = utilConcatBuf(resultBuffer, completeCertificateReferences.makeAttribute().toSchema().toBER(false));
resultBuffer = utilConcatBuf(resultBuffer, completeRevocationReferences.makeAttribute().toSchema().toBER(false));
},
error => Promise.reject(error)
);
//endregion
//region Make hash of signature
sequence = sequence.then(
() => crypto.digest({ name: hashAlgorithm }, resultBuffer),
error => Promise.reject(error)
);
//endregion
return sequence;
}
//**********************************************************************************
/**
* Create "CAdES-C-Timestamp" CAdES attribute
* @param {Object} parameters Additional parameters for making attribute
* @returns {Attribute}
*/
makeAttribute(parameters)
{
//region Initial variables
let tspResponse;
//endregion
//region Check input parameters
if("tspResponse" in parameters)
tspResponse = parameters.tspResponse;
else
{
if("tspResponse" in this)
tspResponse = this.tspResponse;
else
throw new Error("Parameter \"tspResponse\" is mandatory for making \"CAdES-C-Timestamp\" attribute");
}
this.tspResponse = tspResponse;
//endregion
//region Change type of "tspResponse"
const asn1 = asn1js.fromBER(tspResponse);
tspResponse = new TimeStampResp({ schema: asn1.result });
//endregion
//region Initialize internal variables from "tspResponse"
if("timeStampToken" in tspResponse)
this.fromSchema(tspResponse.timeStampToken.toSchema());
else
throw new Error("No neccessary \"timeStampToken\" inside \"tspResponse\"");
//endregion
//region Create and return attribute
return new Attribute({
type: "1.2.840.113549.1.9.16.2.25",
values: [
this.toSchema()
]
});
//endregion
}
//**********************************************************************************
}
//**************************************************************************************