Comparing version 2.1.56 to 2.1.57
@@ -6,4 +6,115 @@ "use strict"; | ||
}); | ||
exports.SignedCertificateTimestamp = undefined; | ||
exports.verifySCTsForCertificate = exports.SignedCertificateTimestamp = undefined; | ||
//************************************************************************************** | ||
/** | ||
* Verify SignedCertificateTimestamp for specific certificate content | ||
* @param {Certificate} certificate Certificate for which verification would be performed | ||
* @param {Certificate} issuerCertificate Certificate of the issuer of target certificate | ||
* @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) | ||
* @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format | ||
* @param {String} logs.key Public key of the CT Log encoded in BASE-64 format | ||
* @param {Number} [index=-1] Index of SignedCertificateTimestamp inside SignedCertificateTimestampList (for -1 would verify all) | ||
* @return {Array} Array of verification results | ||
*/ | ||
let verifySCTsForCertificate = exports.verifySCTsForCertificate = (() => { | ||
var _ref = _asyncToGenerator(function* (certificate, issuerCertificate, logs, index = -1) { | ||
//region Initial variables | ||
let parsedValue = null; | ||
let tbs; | ||
let issuerId; | ||
const stream = new _bytestreamjs.SeqStream(); | ||
let preCert; | ||
//endregion | ||
//region Get a "crypto" extension | ||
const crypto = (0, _common.getCrypto)(); | ||
if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); | ||
//endregion | ||
//region Remove certificate extension | ||
for (let i = 0; i < certificate.extensions.length; i++) { | ||
switch (certificate.extensions[i].extnID) { | ||
case "1.3.6.1.4.1.11129.2.4.2": | ||
{ | ||
parsedValue = certificate.extensions[i].parsedValue; | ||
if (parsedValue.timestamps.length === 0) throw new Error("Nothing to verify in the certificate"); | ||
certificate.extensions.splice(i, 1); | ||
} | ||
break; | ||
default: | ||
} | ||
} | ||
//endregion | ||
//region Check we do have what to verify | ||
if (parsedValue === null) throw new Error("No SignedCertificateTimestampList extension in the specified certificate"); | ||
//endregion | ||
//region Prepare modifier TBS value | ||
tbs = certificate.encodeTBS().toBER(false); | ||
//endregion | ||
//region Initialize "issuer_key_hash" value | ||
issuerId = yield crypto.digest({ name: "SHA-256" }, new Uint8Array(issuerCertificate.subjectPublicKeyInfo.toSchema().toBER(false))); | ||
//endregion | ||
//region Make final "PreCert" value | ||
stream.appendView(new Uint8Array(issuerId)); | ||
stream.appendUint24(tbs.byteLength); | ||
stream.appendView(new Uint8Array(tbs)); | ||
preCert = stream._stream._buffer.slice(0, stream._length); | ||
//endregion | ||
//region Call verification function for specified index | ||
if (index === -1) { | ||
const verifyArray = []; | ||
var _iteratorNormalCompletion4 = true; | ||
var _didIteratorError4 = false; | ||
var _iteratorError4 = undefined; | ||
try { | ||
for (var _iterator4 = parsedValue.timestamps[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { | ||
const timestamp = _step4.value; | ||
const verifyResult = yield timestamp.verify(logs, preCert, 1); | ||
verifyArray.push(verifyResult); | ||
} | ||
} catch (err) { | ||
_didIteratorError4 = true; | ||
_iteratorError4 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion4 && _iterator4.return) { | ||
_iterator4.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError4) { | ||
throw _iteratorError4; | ||
} | ||
} | ||
} | ||
return verifyArray; | ||
} | ||
if (index >= parsedValue.timestamps.length) index = parsedValue.timestamps.length - 1; | ||
return [yield parsedValue.timestamps[index].verify(logs, preCert, 1)]; | ||
//endregion | ||
}); | ||
return function verifySCTsForCertificate(_x, _x2, _x3) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
})(); | ||
//********************************************************************************** | ||
var _asn1js = require("asn1js"); | ||
@@ -17,4 +128,14 @@ | ||
var _common = require("./common.js"); | ||
var _PublicKeyInfo = require("./PublicKeyInfo.js"); | ||
var _PublicKeyInfo2 = _interopRequireDefault(_PublicKeyInfo); | ||
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; } } | ||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } | ||
//************************************************************************************** | ||
@@ -301,2 +422,90 @@ class SignedCertificateTimestamp { | ||
//********************************************************************************** | ||
/** | ||
* Verify SignedCertificateTimestamp for specific input data | ||
* @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) | ||
* @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format | ||
* @param {String} logs.key Public key of the CT Log encoded in BASE-64 format | ||
* @param {ArrayBuffer} data Data to verify signature against. Could be encoded Certificate or encoded PreCert | ||
* @param {Number} [dataType=0] Type = 0 (data is encoded Certificate), type = 1 (data is encoded PreCert) | ||
* @return {Promise<void>} | ||
*/ | ||
verify(logs, data, dataType = 0) { | ||
var _this = this; | ||
return _asyncToGenerator(function* () { | ||
//region Initial variables | ||
let logId = (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(_this.logID)); | ||
let publicKeyBase64 = null; | ||
let publicKeyInfo; | ||
let stream = new _bytestreamjs.SeqStream(); | ||
//endregion | ||
//region Found and init public key | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = logs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
const log = _step.value; | ||
if (log.log_id === logId) { | ||
publicKeyBase64 = log.key; | ||
break; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
if (publicKeyBase64 === null) throw new Error(`Public key not found for CT with logId: ${logId}`); | ||
const asn1 = asn1js.fromBER((0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(publicKeyBase64))); | ||
if (asn1.offset === -1) throw new Error(`Incorrect key value for CT Log with logId: ${logId}`); | ||
publicKeyInfo = new _PublicKeyInfo2.default({ schema: asn1.result }); | ||
//endregion | ||
//region Initialize signed data block | ||
stream.appendChar(0x00); // sct_version | ||
stream.appendChar(0x00); // signature_type = certificate_timestamp | ||
const timeBuffer = new ArrayBuffer(8); | ||
const timeView = new Uint8Array(timeBuffer); | ||
const baseArray = (0, _pvutils.utilToBase)(_this.timestamp.valueOf(), 8); | ||
timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength); | ||
stream.appendView(timeView); | ||
stream.appendUint16(dataType); | ||
if (dataType === 0) stream.appendUint24(data.byteLength); | ||
stream.appendView(new Uint8Array(data)); | ||
stream.appendUint16(_this.extensions.byteLength); | ||
if (_this.extensions.byteLength !== 0) stream.appendView(new Uint8Array(_this.extensions)); | ||
//endregion | ||
//region Perform verification | ||
return (0, _common.getEngine)().subtle.verifyWithPublicKey(stream._stream._buffer.slice(0, stream._length), { valueBlock: { valueHex: _this.signature.toBER(false) } }, publicKeyInfo, { algorithmId: "" }, "SHA-256"); | ||
//endregion | ||
})(); | ||
} | ||
//********************************************************************************** | ||
} | ||
@@ -416,9 +625,9 @@ exports.SignedCertificateTimestamp = SignedCertificateTimestamp; //************************************************************************************** | ||
//region Get overall length | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator = this.timestamps[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
const timestamp = _step.value; | ||
for (var _iterator2 = this.timestamps[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
const timestamp = _step2.value; | ||
@@ -431,12 +640,12 @@ const timestampStream = timestamp.toStream(); | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
@@ -449,9 +658,9 @@ } | ||
//region Set data from all timestamps | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
var _iteratorNormalCompletion3 = true; | ||
var _didIteratorError3 = false; | ||
var _iteratorError3 = undefined; | ||
try { | ||
for (var _iterator2 = timestampsData[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
const timestamp = _step2.value; | ||
for (var _iterator3 = timestampsData[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { | ||
const timestamp = _step3.value; | ||
@@ -461,12 +670,12 @@ stream.appendView(timestamp.stream.view); | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
_didIteratorError3 = true; | ||
_iteratorError3 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
if (!_iteratorNormalCompletion3 && _iterator3.return) { | ||
_iterator3.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
if (_didIteratorError3) { | ||
throw _iteratorError3; | ||
} | ||
@@ -489,4 +698,3 @@ } | ||
//********************************************************************************** | ||
} | ||
exports.default = SignedCertificateTimestampList; //************************************************************************************** | ||
}exports.default = SignedCertificateTimestampList; | ||
//# sourceMappingURL=SignedCertificateTimestampList.js.map |
@@ -101,4 +101,4 @@ { | ||
"name": "pkijs", | ||
"version": "2.1.56", | ||
"version": "2.1.57", | ||
"license": "MIT" | ||
} |
# PKIjs | ||
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/PeculiarVentures/PKI.js/blob/master/LICENSE) | ||
[![CircleCI](https://img.shields.io/circleci/project/github/PeculiarVentures/PKI.js.svg)](https://circleci.com/gh/PeculiarVentures/PKI.js) | ||
[![CircleCI](https://circleci.com/gh/PeculiarVentures/PKI.js/tree/master.svg?style=svg)](https://circleci.com/gh/PeculiarVentures/PKI.js/tree/master) | ||
[![Known Vulnerabilities](https://snyk.io/test/github/PeculiarVentures/PKI.js/badge.svg)](https://snyk.io/test/github/PeculiarVentures/PKI.js) [![Coverage Status](https://coveralls.io/repos/github/PeculiarVentures/PKI.js/badge.svg)](https://coveralls.io/github/PeculiarVentures/PKI.js) | ||
@@ -6,0 +6,0 @@ |
import * as asn1js from "asn1js"; | ||
import { getParametersValue, utilFromBase, utilToBase, bufferToHexCodes } from "pvutils"; | ||
import { getParametersValue, utilFromBase, utilToBase, bufferToHexCodes, toBase64, fromBase64, arrayBufferToString, stringToArrayBuffer } from "pvutils"; | ||
import { ByteStream, SeqStream } from "bytestreamjs"; | ||
import { getCrypto, getEngine } from "./common.js"; | ||
import PublicKeyInfo from "./PublicKeyInfo.js"; | ||
//************************************************************************************** | ||
@@ -305,2 +307,78 @@ export class SignedCertificateTimestamp | ||
//********************************************************************************** | ||
/** | ||
* Verify SignedCertificateTimestamp for specific input data | ||
* @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) | ||
* @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format | ||
* @param {String} logs.key Public key of the CT Log encoded in BASE-64 format | ||
* @param {ArrayBuffer} data Data to verify signature against. Could be encoded Certificate or encoded PreCert | ||
* @param {Number} [dataType=0] Type = 0 (data is encoded Certificate), type = 1 (data is encoded PreCert) | ||
* @return {Promise<void>} | ||
*/ | ||
async verify(logs, data, dataType = 0) | ||
{ | ||
//region Initial variables | ||
let logId = toBase64(arrayBufferToString(this.logID)); | ||
let publicKeyBase64 = null; | ||
let publicKeyInfo; | ||
let stream = new SeqStream(); | ||
//endregion | ||
//region Found and init public key | ||
for(const log of logs) | ||
{ | ||
if(log.log_id === logId) | ||
{ | ||
publicKeyBase64 = log.key; | ||
break; | ||
} | ||
} | ||
if(publicKeyBase64 === null) | ||
throw new Error(`Public key not found for CT with logId: ${logId}`); | ||
const asn1 = asn1js.fromBER(stringToArrayBuffer(fromBase64(publicKeyBase64))); | ||
if(asn1.offset === (-1)) | ||
throw new Error(`Incorrect key value for CT Log with logId: ${logId}`); | ||
publicKeyInfo = new PublicKeyInfo({ schema: asn1.result }); | ||
//endregion | ||
//region Initialize signed data block | ||
stream.appendChar(0x00); // sct_version | ||
stream.appendChar(0x00); // signature_type = certificate_timestamp | ||
const timeBuffer = new ArrayBuffer(8); | ||
const timeView = new Uint8Array(timeBuffer); | ||
const baseArray = utilToBase(this.timestamp.valueOf(), 8); | ||
timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength); | ||
stream.appendView(timeView); | ||
stream.appendUint16(dataType); | ||
if(dataType === 0) | ||
stream.appendUint24(data.byteLength); | ||
stream.appendView(new Uint8Array(data)); | ||
stream.appendUint16(this.extensions.byteLength); | ||
if(this.extensions.byteLength !== 0) | ||
stream.appendView(new Uint8Array(this.extensions)); | ||
//endregion | ||
//region Perform verification | ||
return getEngine().subtle.verifyWithPublicKey( | ||
stream._stream._buffer.slice(0, stream._length), | ||
{ valueBlock: { valueHex: this.signature.toBER(false) } }, | ||
publicKeyInfo, | ||
{ algorithmId: "" }, | ||
"SHA-256" | ||
); | ||
//endregion | ||
} | ||
//********************************************************************************** | ||
} | ||
@@ -374,3 +452,3 @@ //************************************************************************************** | ||
//SignedCertificateTimestampList ::= OCTET STRING | ||
/** | ||
@@ -465,1 +543,91 @@ * @type {Object} | ||
//************************************************************************************** | ||
/** | ||
* Verify SignedCertificateTimestamp for specific certificate content | ||
* @param {Certificate} certificate Certificate for which verification would be performed | ||
* @param {Certificate} issuerCertificate Certificate of the issuer of target certificate | ||
* @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) | ||
* @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format | ||
* @param {String} logs.key Public key of the CT Log encoded in BASE-64 format | ||
* @param {Number} [index=-1] Index of SignedCertificateTimestamp inside SignedCertificateTimestampList (for -1 would verify all) | ||
* @return {Array} Array of verification results | ||
*/ | ||
export async function verifySCTsForCertificate(certificate, issuerCertificate, logs, index = (-1)) | ||
{ | ||
//region Initial variables | ||
let parsedValue = null; | ||
let tbs; | ||
let issuerId; | ||
const stream = new SeqStream(); | ||
let preCert; | ||
//endregion | ||
//region Get a "crypto" extension | ||
const crypto = getCrypto(); | ||
if(typeof crypto === "undefined") | ||
return Promise.reject("Unable to create WebCrypto object"); | ||
//endregion | ||
//region Remove certificate extension | ||
for(let i = 0; i < certificate.extensions.length; i++) | ||
{ | ||
switch(certificate.extensions[i].extnID) | ||
{ | ||
case "1.3.6.1.4.1.11129.2.4.2": | ||
{ | ||
parsedValue = certificate.extensions[i].parsedValue; | ||
if(parsedValue.timestamps.length === 0) | ||
throw new Error("Nothing to verify in the certificate"); | ||
certificate.extensions.splice(i, 1); | ||
} | ||
break; | ||
default: | ||
} | ||
} | ||
//endregion | ||
//region Check we do have what to verify | ||
if(parsedValue === null) | ||
throw new Error("No SignedCertificateTimestampList extension in the specified certificate"); | ||
//endregion | ||
//region Prepare modifier TBS value | ||
tbs = certificate.encodeTBS().toBER(false); | ||
//endregion | ||
//region Initialize "issuer_key_hash" value | ||
issuerId = await crypto.digest({ name: "SHA-256" }, new Uint8Array(issuerCertificate.subjectPublicKeyInfo.toSchema().toBER(false))); | ||
//endregion | ||
//region Make final "PreCert" value | ||
stream.appendView(new Uint8Array(issuerId)); | ||
stream.appendUint24(tbs.byteLength); | ||
stream.appendView(new Uint8Array(tbs)); | ||
preCert = stream._stream._buffer.slice(0, stream._length); | ||
//endregion | ||
//region Call verification function for specified index | ||
if(index === (-1)) | ||
{ | ||
const verifyArray = []; | ||
for(const timestamp of parsedValue.timestamps) | ||
{ | ||
const verifyResult = await timestamp.verify(logs, preCert, 1); | ||
verifyArray.push(verifyResult); | ||
} | ||
return verifyArray; | ||
} | ||
if(index >= parsedValue.timestamps.length) | ||
index = (parsedValue.timestamps.length - 1); | ||
return [await parsedValue.timestamps[index].verify(logs, preCert, 1)]; | ||
//endregion | ||
} | ||
//********************************************************************************** |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4061644
60709