cadesjs
Version:
CAdESjs gives you an ability to make CAdES signatures on pure JavaScript. The libray made with latest CAdES standards in mind
275 lines (221 loc) • 11.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _asn1js = require("asn1js");
var asn1js = _interopRequireWildcard(_asn1js);
var _pvutils = require("pvutils");
var _pkijs = require("pkijs");
var _ATSHashIndex = require("./ATSHashIndex.js");
var _ATSHashIndex2 = _interopRequireDefault(_ATSHashIndex);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
//**************************************************************************************
// noinspection JSUnusedGlobalSymbols
class ArchiveTimeStampV3 extends _pkijs.ContentInfo {
//**********************************************************************************
/**
* Constructor for ArchiveTimeStampV3 class
* @param {Object} [parameters={}]
* @property {Object} [schema] asn1js parsed value
*/
constructor(parameters = {}) {
super(parameters);
//region Internal properties of the object
if ("tspResponse" in parameters)
/**
* @type {ArrayBuffer}
* @description tspResponse
*/
this.tspResponse = (0, _pvutils.getParametersValue)(parameters, "tspResponse", ArchiveTimeStampV3.defaultValues("tspResponse"));
/**
* @type {ATSHashIndex}
* @description aTSHashIndex
*/
this.aTSHashIndex = (0, _pvutils.getParametersValue)(parameters, "aTSHashIndex", ArchiveTimeStampV3.defaultValues("aTSHashIndex"));
//endregion
//region If input argument array contains "schema" for this object
if ("schema" in parameters) this.fromSchema(parameters.schema);
//endregion
}
//**********************************************************************************
/**
* Return default values for all class members
* @param {string} memberName String name for a class member
*/
static defaultValues(memberName) {
switch (memberName) {
case "tspResponse":
return new ArrayBuffer(0);
case "aTSHashIndex":
return new _ATSHashIndex2.default();
default:
throw new Error(`Invalid member name for ArchiveTimeStampV3 class: ${memberName}`);
}
}
//**********************************************************************************
/**
* Compare values with default values for all class members
* @param {string} memberName String name for a class member
* @param {*} memberValue Value to compare with default value
*/
static compareWithDefault(memberName, memberValue) {
switch (memberName) {
case "tspResponse":
return memberValue.byteLength === 0;
case "aTSHashIndex":
// noinspection OverlyComplexBooleanExpressionJS
return "hashIndAlgorithm" in memberValue === false && _ATSHashIndex2.default.compareWithDefault("certificatesHashIndex", memberValue.certificatesHashIndex) && _ATSHashIndex2.default.compareWithDefault("crlsHashIndex", memberValue.crlsHashIndex) && _ATSHashIndex2.default.compareWithDefault("unsignedAttrsHashIndex", memberValue.unsignedAttrsHashIndex);
default:
throw new Error(`Invalid member name for ArchiveTimeStampV3 class: ${memberName}`);
}
}
//**********************************************************************************
/**
* Convert parsed asn1js object into current class
* @param {!Object} schema
* @param {boolean} [initValues=true]
*/
fromSchema(schema, initValues = true) {
super.fromSchema(schema);
if (initValues) {
if (this.contentType !== "1.2.840.113549.1.7.2") throw new Error("Incorrect object schema for archive-time-stamp-v3 attribute: incorrect content type");
this.tspResponse = new _pkijs.TimeStampResp({ timeStampToken: schema });
const cmsSignedData = new _pkijs.SignedData({ schema: this.content });
if (cmsSignedData.signerInfos.length !== 1) throw new Error("Incorrect object schema for archive-time-stamp-v3 attribute: incorrect signerInfos length");
if ("unsignedAttrs" in cmsSignedData.signerInfos[0] === false) throw new Error("Incorrect object schema for archive-time-stamp-v3 attribute: missing unsignedAttrs");
if (cmsSignedData.signerInfos[0].unsignedAttrs.attributes.length !== 1) throw new Error("Incorrect object schema for archive-time-stamp-v3 attribute: incorrect unsignedAttrs length");
const attribute = new _pkijs.Attribute(cmsSignedData.signerInfos[0].unsignedAttrs.attributes[0]);
if (attribute.type !== "0.4.0.1733.2.5") throw new Error("Incorrect object schema for archive-time-stamp-v3 attribute: incorrect type for aTSHashIndex value");
let parsedValue;
try {
parsedValue = new _ATSHashIndex2.default({ schema: attribute.values[0] });
} catch (e) {
throw new Error("Incorrect object schema for archive-time-stamp-v3 attribute: incorrect aTSHashIndex value");
}
this.aTSHashIndex = parsedValue;
}
}
//**********************************************************************************
// 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 content = new ArrayBuffer(0);
let aTSHashIndex = new ArrayBuffer(0);
let resultBuffer = new ArrayBuffer(0);
//endregion
//region Get a "crypto" extension
const crypto = (0, _pkijs.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 ("content" in parameters) content = parameters.content; // ArrayBuffer
else {
if ("eContent" in cmsSignedData.encapContentInfo) {
if (cmsSignedData.encapContentInfo.eContent.idBlock.tagClass === 1 && cmsSignedData.encapContentInfo.eContent.idBlock.tagNumber === 4) {
if (cmsSignedData.encapContentInfo.eContent.idBlock.isConstructed === false) content = cmsSignedData.encapContentInfo.eContent.valueBlock.valueHex;else {
for (let i = 0; i < cmsSignedData.encapContentInfo.eContent.valueBlock.value.length; i++) content = (0, _pvutils.utilConcatBuf)(content, cmsSignedData.encapContentInfo.eContent.valueBlock.value[i].valueBlock.valueHex);
}
} else content = cmsSignedData.encapContentInfo.eContent.valueBlock.valueHex;
} else return Promise.reject("Parameter \"content\" is mandatory for making archive-time-stamp-v3");
}
if ("aTSHashIndex" in parameters) aTSHashIndex = parameters.aTSHashIndex; // ArrayBuffer
else return Promise.reject("Parameter \"aTSHashIndex\" is mandatory for making archive-time-stamp-v3");
//endregion
//region Make hash of initial content
sequence = sequence.then(() => crypto.digest({ name: hashAlgorithm }, content), error => Promise.reject(error));
//endregion
//region Make final stamping buffer
sequence = sequence.then(result => {
//region eContentType
const contentOID = new asn1js.ObjectIdentifier({ value: cmsSignedData.encapContentInfo.eContentType });
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, contentOID.toBER(false));
//endregion
//region message-digest
// noinspection JSCheckFunctionSignatures
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, result);
//endregion
//region version
const version = new asn1js.Integer({ value: cmsSignedData.signerInfos[signerIndex].version });
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, version.toBER(false));
//endregion
//region sid
let sid;
if (cmsSignedData.signerInfos[signerIndex].sid instanceof _pkijs.IssuerAndSerialNumber) sid = cmsSignedData.signerInfos[signerIndex].sid.toSchema();else sid = cmsSignedData.signerInfos[signerIndex].sid;
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, sid.toBER(false));
//endregion
//region digestAlgorithm
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, cmsSignedData.signerInfos[signerIndex].digestAlgorithm.toSchema().toBER(false));
//endregion
//region signedAttrs
if ("signedAttrs" in cmsSignedData.signerInfos[signerIndex]) resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, cmsSignedData.signerInfos[signerIndex].signedAttrs.toSchema().toBER(false));else return Promise.reject("Must be \"signedAttrs\" inside SignerInfo structure. Check correctness of the signed data.");
//endregion
//region signatureAlgorithm
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, cmsSignedData.signerInfos[signerIndex].signatureAlgorithm.toSchema().toBER(false));
//endregion
//region signature
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, cmsSignedData.signerInfos[signerIndex].signature.toBER(false));
//endregion
//region ATSHashIndexV2
resultBuffer = (0, _pvutils.utilConcatBuf)(resultBuffer, aTSHashIndex);
//endregion
return resultBuffer;
}, error => Promise.reject(error));
//endregion
//region Make hash of result buffer
sequence = sequence.then(result => crypto.digest({ name: hashAlgorithm }, result), error => Promise.reject(error));
//endregion
return sequence;
}
//**********************************************************************************
/**
* Create "archive-time-stamp-v3" 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 archive-time-stamp-v3 attribute");
}
this.tspResponse = tspResponse;
//endregion
//region Change type of "tspResponse"
const asn1 = asn1js.fromBER(tspResponse);
tspResponse = new _pkijs.TimeStampResp({ schema: asn1.result });
//endregion
//region Initialize internal variables from "tspResponse"
if ("timeStampToken" in tspResponse) this.fromSchema(tspResponse.timeStampToken.toSchema(), false);else throw new Error("No neccessary \"timeStampToken\" inside \"tspResponse\"");
//endregion
//region Append "ATSHashIndex" into local unsigned attributes
const cmsSignedData = new _pkijs.SignedData({ schema: this.content });
cmsSignedData.signerInfos[0].unsignedAttrs = new _pkijs.SignedAndUnsignedAttributes({
type: 1, // UnsignedAttributes
attributes: [this.aTSHashIndex.makeAttribute()]
});
this.content = cmsSignedData.toSchema();
//endregion
//region Create and return attribute
return new _pkijs.Attribute({
type: "0.4.0.1733.2.4",
values: [this.toSchema()]
});
//endregion
}
//**********************************************************************************
}
exports.default = ArchiveTimeStampV3; //**************************************************************************************
//# sourceMappingURL=ArchiveTimeStampV3.js.map