pkijs
Version:
Public Key Infrastructure (PKI) is the basis of how identity and key management is performed on the web today. PKIjs is a pure JavaScript library implementing the formats that are used in PKI applications. It is built on WebCrypto and aspires to make it p
1,663 lines (1,293 loc) • 81.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _pvutils = require("pvutils");
var _common = require("./common.js");
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
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"); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
//**************************************************************************************
var CertificateChainValidationEngine = function () {
//**********************************************************************************
/**
* Constructor for CertificateChainValidationEngine class
* @param {Object} [parameters={}]
* @property {Object} [schema] asn1js parsed value
*/
function CertificateChainValidationEngine() {
var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, CertificateChainValidationEngine);
//region Internal properties of the object
/**
* @type {Array.<Certificate>}
* @description Array of pre-defined trusted (by user) certificates
*/
this.trustedCerts = (0, _pvutils.getParametersValue)(parameters, "trustedCerts", this.defaultValues("trustedCerts"));
/**
* @type {Array.<Certificate>}
* @description Array with certificate chain. Could be only one end-user certificate in there!
*/
this.certs = (0, _pvutils.getParametersValue)(parameters, "certs", this.defaultValues("certs"));
/**
* @type {Array.<CertificateRevocationList>}
* @description Array of all CRLs for all certificates from certificate chain
*/
this.crls = (0, _pvutils.getParametersValue)(parameters, "crls", this.defaultValues("crls"));
/**
* @type {Array}
* @description Array of all OCSP responses
*/
this.ocsps = (0, _pvutils.getParametersValue)(parameters, "ocsps", this.defaultValues("ocsps"));
/**
* @type {Date}
* @description The date at which the check would be
*/
this.checkDate = (0, _pvutils.getParametersValue)(parameters, "checkDate", this.defaultValues("checkDate"));
/**
* @type {Function}
* @description The date at which the check would be
*/
this.findOrigin = (0, _pvutils.getParametersValue)(parameters, "findOrigin", this.defaultValues("findOrigin"));
/**
* @type {Function}
* @description The date at which the check would be
*/
this.findIssuer = (0, _pvutils.getParametersValue)(parameters, "findIssuer", this.defaultValues("findIssuer"));
//endregion
}
//**********************************************************************************
_createClass(CertificateChainValidationEngine, [{
key: "defaultFindIssuer",
//**********************************************************************************
value: function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(certificate, validationEngine) {
var result, keyIdentifier, authorityCertIssuer, authorityCertSerialNumber, verificationResult, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, extension, checkCertificate, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, trustedCert, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, intermediateCert, i, _verificationResult;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
checkCertificate = function checkCertificate(possibleIssuer) {
//region Firstly search for appropriate extensions
if (keyIdentifier !== null) {
if ("extensions" in possibleIssuer) {
var extensionFound = false;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = possibleIssuer.extensions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _extension = _step2.value;
if (_extension.extnID === "2.5.29.14") // SubjectKeyIdentifier
{
extensionFound = true;
if ((0, _pvutils.isEqualBuffer)(_extension.parsedValue.valueBlock.valueHex, keyIdentifier.valueBlock.valueHex)) result.push(possibleIssuer);
break;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
if (extensionFound) return;
}
}
//endregion
//region Now search for authorityCertSerialNumber
var authorityCertSerialNumberEqual = false;
if (authorityCertSerialNumber !== null) authorityCertSerialNumberEqual = possibleIssuer.serialNumber.isEqual(authorityCertSerialNumber);
//endregion
//region And at least search for Issuer data
if (authorityCertIssuer !== null) {
if (possibleIssuer.subject.isEqual(authorityCertIssuer)) {
if (authorityCertSerialNumberEqual) result.push(possibleIssuer);
}
} else {
if (certificate.issuer.isEqual(possibleIssuer.subject)) result.push(possibleIssuer);
}
//endregion
};
//region Initial variables
result = [];
keyIdentifier = null;
authorityCertIssuer = null;
authorityCertSerialNumber = null;
//endregion
//region Speed-up searching in case of self-signed certificates
if (!certificate.subject.isEqual(certificate.issuer)) {
_context.next = 16;
break;
}
_context.prev = 6;
_context.next = 9;
return certificate.verify();
case 9:
verificationResult = _context.sent;
if (!(verificationResult === true)) {
_context.next = 12;
break;
}
return _context.abrupt("return", [certificate]);
case 12:
_context.next = 16;
break;
case 14:
_context.prev = 14;
_context.t0 = _context["catch"](6);
case 16:
if (!("extensions" in certificate)) {
_context.next = 44;
break;
}
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
_context.prev = 20;
_iterator = certificate.extensions[Symbol.iterator]();
case 22:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
_context.next = 30;
break;
}
extension = _step.value;
if (!(extension.extnID === "2.5.29.35")) {
_context.next = 27;
break;
}
if ("keyIdentifier" in extension.parsedValue) keyIdentifier = extension.parsedValue.keyIdentifier;else {
if ("authorityCertIssuer" in extension.parsedValue) authorityCertIssuer = extension.parsedValue.authorityCertIssuer;
if ("authorityCertSerialNumber" in extension.parsedValue) authorityCertSerialNumber = extension.parsedValue.authorityCertSerialNumber;
}
return _context.abrupt("break", 30);
case 27:
_iteratorNormalCompletion = true;
_context.next = 22;
break;
case 30:
_context.next = 36;
break;
case 32:
_context.prev = 32;
_context.t1 = _context["catch"](20);
_didIteratorError = true;
_iteratorError = _context.t1;
case 36:
_context.prev = 36;
_context.prev = 37;
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
case 39:
_context.prev = 39;
if (!_didIteratorError) {
_context.next = 42;
break;
}
throw _iteratorError;
case 42:
return _context.finish(39);
case 43:
return _context.finish(36);
case 44:
//endregion
//region Search in Trusted Certificates
_iteratorNormalCompletion3 = true;
_didIteratorError3 = false;
_iteratorError3 = undefined;
_context.prev = 47;
for (_iterator3 = validationEngine.trustedCerts[Symbol.iterator](); !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
trustedCert = _step3.value;
checkCertificate(trustedCert);
} //endregion
//region Search in Intermediate Certificates
_context.next = 55;
break;
case 51:
_context.prev = 51;
_context.t2 = _context["catch"](47);
_didIteratorError3 = true;
_iteratorError3 = _context.t2;
case 55:
_context.prev = 55;
_context.prev = 56;
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
case 58:
_context.prev = 58;
if (!_didIteratorError3) {
_context.next = 61;
break;
}
throw _iteratorError3;
case 61:
return _context.finish(58);
case 62:
return _context.finish(55);
case 63:
_iteratorNormalCompletion4 = true;
_didIteratorError4 = false;
_iteratorError4 = undefined;
_context.prev = 66;
for (_iterator4 = validationEngine.certs[Symbol.iterator](); !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
intermediateCert = _step4.value;
checkCertificate(intermediateCert);
} //endregion
//region Now perform certificate verification checking
_context.next = 74;
break;
case 70:
_context.prev = 70;
_context.t3 = _context["catch"](66);
_didIteratorError4 = true;
_iteratorError4 = _context.t3;
case 74:
_context.prev = 74;
_context.prev = 75;
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
case 77:
_context.prev = 77;
if (!_didIteratorError4) {
_context.next = 80;
break;
}
throw _iteratorError4;
case 80:
return _context.finish(77);
case 81:
return _context.finish(74);
case 82:
i = 0;
case 83:
if (!(i < result.length)) {
_context.next = 97;
break;
}
_context.prev = 84;
_context.next = 87;
return certificate.verify(result[i]);
case 87:
_verificationResult = _context.sent;
if (_verificationResult === false) result.splice(i, 1);
_context.next = 94;
break;
case 91:
_context.prev = 91;
_context.t4 = _context["catch"](84);
result.splice(i, 1); // Something wrong, remove the certificate
case 94:
i++;
_context.next = 83;
break;
case 97:
return _context.abrupt("return", result);
case 98:
case "end":
return _context.stop();
}
}
}, _callee, this, [[6, 14], [20, 32, 36, 44], [37,, 39, 43], [47, 51, 55, 63], [56,, 58, 62], [66, 70, 74, 82], [75,, 77, 81], [84, 91]]);
}));
function defaultFindIssuer(_x2, _x3) {
return _ref.apply(this, arguments);
}
return defaultFindIssuer;
}()
//**********************************************************************************
/**
* Return default values for all class members
* @param {string} memberName String name for a class member
*/
}, {
key: "defaultValues",
value: function defaultValues(memberName) {
switch (memberName) {
case "trustedCerts":
return [];
case "certs":
return [];
case "crls":
return [];
case "ocsps":
return [];
case "checkDate":
return new Date();
case "findOrigin":
return CertificateChainValidationEngine.defaultFindOrigin;
case "findIssuer":
return this.defaultFindIssuer;
default:
throw new Error("Invalid member name for CertificateChainValidationEngine class: " + memberName);
}
}
//**********************************************************************************
}, {
key: "sort",
value: function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7() {
//endregion
//region Building certificate path
var buildPath = function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(certificate) {
var result, checkUnique, findIssuerResult, i, buildPathResult, j, copy;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
checkUnique = function checkUnique(array) {
var unique = true;
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < array.length; j++) {
if (j === i) continue;
if (array[i] === array[j]) {
unique = false;
break;
}
}
if (!unique) break;
}
return unique;
};
result = [];
//region Aux function checking array for unique elements
_context2.next = 4;
return _this.findIssuer(certificate, _this);
case 4:
findIssuerResult = _context2.sent;
if (!(findIssuerResult.length === 0)) {
_context2.next = 7;
break;
}
throw new Error("No valid certificate paths found");
case 7:
i = 0;
case 8:
if (!(i < findIssuerResult.length)) {
_context2.next = 19;
break;
}
if (!(0, _pvutils.isEqualBuffer)(findIssuerResult[i].tbs, certificate.tbs)) {
_context2.next = 12;
break;
}
result.push([findIssuerResult[i]]);
return _context2.abrupt("continue", 16);
case 12:
_context2.next = 14;
return buildPath(findIssuerResult[i]);
case 14:
buildPathResult = _context2.sent;
for (j = 0; j < buildPathResult.length; j++) {
copy = buildPathResult[j].slice();
copy.splice(0, 0, findIssuerResult[i]);
if (checkUnique(copy)) result.push(copy);else result.push(buildPathResult[j]);
}
case 16:
i++;
_context2.next = 8;
break;
case 19:
return _context2.abrupt("return", result);
case 20:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return function buildPath(_x4) {
return _ref3.apply(this, arguments);
};
}();
//endregion
//region Find CRL for specific certificate
var findCRL = function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(certificate) {
var issuerCertificates, crls, crlsAndCertificates, i, j, _result;
return regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
//region Initial variables
issuerCertificates = [];
crls = [];
crlsAndCertificates = [];
//endregion
//region Find all possible CRL issuers
issuerCertificates.push.apply(issuerCertificates, _toConsumableArray(localCerts.filter(function (element) {
return certificate.issuer.isEqual(element.subject);
})));
if (!(issuerCertificates.length === 0)) {
_context3.next = 6;
break;
}
return _context3.abrupt("return", {
status: 1,
statusMessage: "No certificate's issuers"
});
case 6:
//endregion
//region Find all CRLs for crtificate's issuer
crls.push.apply(crls, _toConsumableArray(_this.crls.filter(function (element) {
return element.issuer.isEqual(certificate.issuer);
})));
if (!(crls.length === 0)) {
_context3.next = 9;
break;
}
return _context3.abrupt("return", {
status: 1,
statusMessage: "No CRLs for specific certificate issuer"
});
case 9:
i = 0;
case 10:
if (!(i < crls.length)) {
_context3.next = 32;
break;
}
if (!(crls[i].nextUpdate.value < _this.checkDate)) {
_context3.next = 13;
break;
}
return _context3.abrupt("continue", 29);
case 13:
j = 0;
case 14:
if (!(j < issuerCertificates.length)) {
_context3.next = 29;
break;
}
_context3.prev = 15;
_context3.next = 18;
return crls[i].verify({ issuerCertificate: issuerCertificates[j] });
case 18:
_result = _context3.sent;
if (!_result) {
_context3.next = 22;
break;
}
crlsAndCertificates.push({
crl: crls[i],
certificate: issuerCertificates[j]
});
return _context3.abrupt("break", 29);
case 22:
_context3.next = 26;
break;
case 24:
_context3.prev = 24;
_context3.t0 = _context3["catch"](15);
case 26:
j++;
_context3.next = 14;
break;
case 29:
i++;
_context3.next = 10;
break;
case 32:
if (!crlsAndCertificates.length) {
_context3.next = 34;
break;
}
return _context3.abrupt("return", {
status: 0,
statusMessage: "",
result: crlsAndCertificates
});
case 34:
return _context3.abrupt("return", {
status: 1,
statusMessage: "No valid CRLs found"
});
case 35:
case "end":
return _context3.stop();
}
}
}, _callee3, this, [[15, 24]]);
}));
return function findCRL(_x5) {
return _ref4.apply(this, arguments);
};
}();
//endregion
//region Find OCSP for specific certificate
var findOCSP = function () {
var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(certificate, issuerCertificate) {
var hashAlgorithm, i, _result2;
return regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
//region Get hash algorithm from certificate
hashAlgorithm = (0, _common.getAlgorithmByOID)(certificate.signatureAlgorithm.algorithmId);
if (!("name" in hashAlgorithm === false)) {
_context4.next = 3;
break;
}
return _context4.abrupt("return", 1);
case 3:
if (!("hash" in hashAlgorithm === false)) {
_context4.next = 5;
break;
}
return _context4.abrupt("return", 1);
case 5:
i = 0;
case 6:
if (!(i < _this.ocsps.length)) {
_context4.next = 17;
break;
}
_context4.next = 9;
return _this.ocsps[i].getCertificateStatus(certificate, issuerCertificate);
case 9:
_result2 = _context4.sent;
if (!_result2.isForCertificate) {
_context4.next = 14;
break;
}
if (!(_result2.status === 0)) {
_context4.next = 13;
break;
}
return _context4.abrupt("return", 0);
case 13:
return _context4.abrupt("return", 1);
case 14:
i++;
_context4.next = 6;
break;
case 17:
return _context4.abrupt("return", 2);
case 18:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
return function findOCSP(_x6, _x7) {
return _ref5.apply(this, arguments);
};
}();
//endregion
//region Check for certificate to be CA
var checkForCA = function () {
var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5(certificate) {
var needToCheckCRL = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isCA, mustBeCA, keyUsagePresent, cRLSign, j, view;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
//region Initial variables
isCA = false;
mustBeCA = false;
keyUsagePresent = false;
cRLSign = false;
//endregion
if (!("extensions" in certificate)) {
_context5.next = 20;
break;
}
j = 0;
case 6:
if (!(j < certificate.extensions.length)) {
_context5.next = 14;
break;
}
if (!(certificate.extensions[j].critical === true && "parsedValue" in certificate.extensions[j] === false)) {
_context5.next = 9;
break;
}
return _context5.abrupt("return", {
result: false,
resultCode: 6,
resultMessage: "Unable to parse critical certificate extension: " + certificate.extensions[j].extnID
});
case 9:
if (certificate.extensions[j].extnID === "2.5.29.15") // KeyUsage
{
keyUsagePresent = true;
view = new Uint8Array(certificate.extensions[j].parsedValue.valueBlock.valueHex);
if ((view[0] & 0x04) === 0x04) // Set flag "keyCertSign"
mustBeCA = true;
if ((view[0] & 0x02) === 0x02) // Set flag "cRLSign"
cRLSign = true;
}
if (certificate.extensions[j].extnID === "2.5.29.19") // BasicConstraints
{
if ("cA" in certificate.extensions[j].parsedValue) {
if (certificate.extensions[j].parsedValue.cA === true) isCA = true;
}
}
case 11:
j++;
_context5.next = 6;
break;
case 14:
if (!(mustBeCA === true && isCA === false)) {
_context5.next = 16;
break;
}
return _context5.abrupt("return", {
result: false,
resultCode: 3,
resultMessage: "Unable to build certificate chain - using \"keyCertSign\" flag set without BasicConstaints"
});
case 16:
if (!(keyUsagePresent === true && isCA === true && mustBeCA === false)) {
_context5.next = 18;
break;
}
return _context5.abrupt("return", {
result: false,
resultCode: 4,
resultMessage: "Unable to build certificate chain - \"keyCertSign\" flag was not set"
});
case 18:
if (!(isCA === true && keyUsagePresent === true && needToCheckCRL && cRLSign === false)) {
_context5.next = 20;
break;
}
return _context5.abrupt("return", {
result: false,
resultCode: 5,
resultMessage: "Unable to build certificate chain - intermediate certificate must have \"cRLSign\" key usage flag"
});
case 20:
if (!(isCA === false)) {
_context5.next = 22;
break;
}
return _context5.abrupt("return", {
result: false,
resultCode: 7,
resultMessage: "Unable to build certificate chain - more than one possible end-user certificate"
});
case 22:
return _context5.abrupt("return", {
result: true,
resultCode: 0,
resultMessage: ""
});
case 23:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
return function checkForCA(_x9) {
return _ref6.apply(this, arguments);
};
}();
//endregion
//region Basic check for certificate path
var basicCheck = function () {
var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6(path, checkDate) {
var i, _i, _i2, ocspResult, crlResult, j, isCertificateRevoked, isCertificateCA, _i3, _result3;
return regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
i = 0;
case 1:
if (!(i < path.length)) {
_context6.next = 7;
break;
}
if (!(path[i].notBefore.value > checkDate || path[i].notAfter.value < checkDate)) {
_context6.next = 4;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 8,
resultMessage: "The certificate is either not yet valid or expired"
});
case 4:
i++;
_context6.next = 1;
break;
case 7:
if (!(path.length < 2)) {
_context6.next = 9;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 9,
resultMessage: "Too short certificate path"
});
case 9:
_i = path.length - 2;
case 10:
if (!(_i >= 0)) {
_context6.next = 17;
break;
}
if (!(path[_i].issuer.isEqual(path[_i].subject) === false)) {
_context6.next = 14;
break;
}
if (!(path[_i].issuer.isEqual(path[_i + 1].subject) === false)) {
_context6.next = 14;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 10,
resultMessage: "Incorrect name chaining"
});
case 14:
_i--;
_context6.next = 10;
break;
case 17:
if (!(_this.crls.length !== 0 || _this.ocsps.length !== 0)) {
_context6.next = 58;
break;
}
_i2 = 0;
case 19:
if (!(_i2 < path.length - 2)) {
_context6.next = 58;
break;
}
//region Initial variables
ocspResult = void 0;
crlResult = void 0;
//endregion
//region Check OCSPs first
if (!(_this.ocsps.length !== 0)) {
_context6.next = 32;
break;
}
_context6.next = 25;
return findOCSP(path[_i2], path[_i2 + 1]);
case 25:
ocspResult = _context6.sent;
_context6.t0 = ocspResult;
_context6.next = _context6.t0 === 0 ? 29 : _context6.t0 === 1 ? 30 : _context6.t0 === 2 ? 31 : 32;
break;
case 29:
return _context6.abrupt("continue", 55);
case 30:
return _context6.abrupt("return", {
result: false,
resultCode: 12,
resultMessage: "One of certificates was revoked via OCSP response"
});
case 31:
return _context6.abrupt("break", 32);
case 32:
if (!(_this.crls.length !== 0)) {
_context6.next = 53;
break;
}
_context6.next = 35;
return findCRL(path[_i2]);
case 35:
crlResult = _context6.sent;
if (!crlResult.status) {
_context6.next = 38;
break;
}
throw {
result: false,
resultCode: 11,
resultMessage: "No revocation values found for one of certificates: " + crlResult.statusMessage
};
case 38:
j = 0;
case 39:
if (!(j < crlResult.result.length)) {
_context6.next = 51;
break;
}
//region Check that the CRL issuer certificate have not been revoked
isCertificateRevoked = crlResult.result[j].crl.isCertificateRevoked(path[_i2]);
if (!isCertificateRevoked) {
_context6.next = 43;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 12,
resultMessage: "One of certificates had been revoked"
});
case 43:
_context6.next = 45;
return checkForCA(crlResult.result[j].certificate, true);
case 45:
isCertificateCA = _context6.sent;
if (!(isCertificateCA.result === false)) {
_context6.next = 48;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 13,
resultMessage: "CRL issuer certificate is not a CA certificate or does not have crlSign flag"
});
case 48:
j++;
_context6.next = 39;
break;
case 51:
_context6.next = 55;
break;
case 53:
if (!(ocspResult === 2)) {
_context6.next = 55;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 11,
resultMessage: "No revocation values found for one of certificates"
});
case 55:
_i2++;
_context6.next = 19;
break;
case 58:
_i3 = 1;
case 59:
if (!(_i3 < path.length)) {
_context6.next = 68;
break;
}
_context6.next = 62;
return checkForCA(path[_i3]);
case 62:
_result3 = _context6.sent;
if (!(_result3.result === false)) {
_context6.next = 65;
break;
}
return _context6.abrupt("return", {
result: false,
resultCode: 14,
resultMessage: "One of intermediate certificates is not a CA certificate"
});
case 65:
_i3++;
_context6.next = 59;
break;
case 68:
return _context6.abrupt("return", {
result: true
});
case 69:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
return function basicCheck(_x10, _x11) {
return _ref7.apply(this, arguments);
};
}();
//endregion
//region Do main work
//region Initialize "localCerts" by value of "_this.certs" + "_this.trustedCerts" arrays
var localCerts, _this, i, j, result, certificatePath, _i4, found, _j, _certificate, k, shortestLength, shortestIndex, _i5, _i6;
return regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
//region Initial variables
localCerts = [];
_this = this;
localCerts.push.apply(localCerts, _toConsumableArray(_this.trustedCerts));
localCerts.push.apply(localCerts, _toConsumableArray(_this.certs));
//endregion
//region Check all certificates for been unique
i = 0;
case 5:
if (!(i < localCerts.length)) {
_context7.next = 20;
break;
}
j = 0;
case 7:
if (!(j < localCerts.length)) {
_context7.next = 17;
break;
}
if (!(i === j)) {
_context7.next = 10;
break;
}
return _context7.abrupt("continue", 14);
case 10:
if (!(0, _pvutils.isEqualBuffer)(localCerts[i].tbs, localCerts[j].tbs)) {
_context7.next = 14;
break;
}
localCerts.splice(j, 1);
i = 0;
return _context7.abrupt("break", 17);
case 14:
j++;
_context7.next = 7;
break;
case 17:
i++;
_context7.next = 5;
break;
case 20:
//endregion
//region Initial variables
result = void 0;
certificatePath = [localCerts[localCerts.length - 1]]; // The "end entity" certificate must be the least in "certs" array
//endregion
//region Build path for "end entity" certificate
_context7.next = 24;
return buildPath(localCerts[localCerts.length - 1]);
case 24:
result = _context7.sent;
if (!(result.length === 0)) {
_context7.next = 27;
break;
}
return _context7.abrupt("return", {
result: false,
resultCode: 60,
resultMessage: "Unable to find certificate path"
});
case 27:
_i4 = 0;
case 28:
if (!(_i4 < result.length)) {
_context7.next = 50;
break;
}
found = false;
_j = 0;
case 31:
if (!(_j < result[_i4].length)) {
_context7.next = 46;
break;
}
_certificate = result[_i4][_j];
k = 0;
case 34:
if (!(k < _this.trustedCerts.length)) {
_context7.next = 41;
break;
}
if (!(0, _pvutils.isEqualBuffer)(_certificate.tbs, _this.trustedCerts[k].tbs)) {
_context7.next = 38;
break;
}
found = true;
return _context7.abrupt("break", 41);
case 38:
k++;
_context7.next = 34;
break;
case 41:
if (!found) {
_context7.next = 43;
break;
}
return _context7.abrupt("break", 46);
case 43:
_j++;
_context7.next = 31;
break;
case 46:
if (!found) {
result.splice(_i4, 1);
_i4 = 0;
}
case 47:
_i4++;
_context7.next = 28;
break;
case 50:
if (!(result.length === 0)) {
_context7.next = 52;
break;
}
throw {
result: false,
resultCode: 97,
resultMessage: "No valid certificate paths found"
};
case 52:
//endregion
//region Find shortest certificate path (for the moment it is the only criteria)
shortestLength = result[0].length;
shortestIndex = 0;
for (_i5 = 0; _i5 < result.length; _i5++) {
if (result[_i5].length < shortestLength) {
shortestLength = result[_i5].length;
shortestIndex = _i5;
}
}
//endregion
//region Create certificate path for basic check
for (_i6 = 0; _i6 < result[shortestIndex].length; _i6++) {
certificatePath.push(result[shortestIndex][_i6]);
} //endregion
//region Perform basic checking for all certificates in the path
_context7.next = 58;
return basicCheck(certificatePath, _this.checkDate);
case 58:
result = _context7.sent;
if (!(result.result === false)) {
_context7.next = 61;
break;
}
throw result;
case 61:
return _context7.abrupt("return", certificatePath);
case 62:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
function sort() {
return _ref2.apply(this, arguments);
}
return sort;
}()
//**********************************************************************************
/**
* Major verification function for certificate chain.
* @param {{initialPolicySet, initialExplicitPolicy, initialPolicyMappingInhibit, initialInhibitPolicy, initialPermittedSubtreesSet, initialExcludedSubtreesSet, initialRequiredNameForms}} [parameters]
* @returns {Promise}
*/
}, {
key: "verify",
value: function () {
var _ref8 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8() {
var parameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var compareDNSName, compareRFC822Name, compareUniformResourceIdentifier, compareIPAddress, compareDirectoryName, initialPolicySet, initialExplicitPolicy, initialPolicyMappingInhibit, initialInhibitPolicy, initialPermittedSubtreesSet, initialExcludedSubtreesSet, initialRequiredNameForms, explicitPolicyIndicator, policyMappingInhibitIndicator, inhibitAnyPolicyIndicator, pendingConstraints, explicitPolicyPending, policyMappingInhibitPending, inhibitAnyPolicyPending, permittedSubtrees, excludedSubtrees, requiredNameForms, pathDepth, allPolicies, policiesAndCerts, anyPolicyArray, ii, policyMappings, certPolicies, explicitPolicyStart, i, j, s, k, policyIndex, _s, certArray, _policyIndex, searchAnyPolicy, _i10, _k, issuerDomainPolicyIndex, subjectDomainPolicyIndex, n, _j2, m, _i11, _j3, authConstrPolicies, _i12, found, _j4, anyPolicyFound, _k2, userConstrPolicies, _i13, _j5, policyResult, _i14, subjectAltNames, certPermittedSubtrees, certExcludedSubtrees, _j6, formFound, _j7, _k3, constrGroups, _j8, p, groupPermitted, valueExists, group, _j9, _k4, _k5, _k6, _k7, _k8, excluded, _j10, _k9, _k10, _k11, _k12, _k13;
return regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
compareDirectoryName = function compareDirectoryName(name, constraint) {
/// <summary>Compare two directoryName values</summary>
/// <param name="name" type="in_window.org.pkijs.simpl.RDN">directoryName from name</param>
/// <param name="constraint" type="in_window.org.pkijs.simpl.RDN">Constraint for directoryName from name</param>
/// <param name="any" type="Boolean">Boolean flag - should be comparision interrupted after first match or we need to match all "constraints" parts</param>
/// <returns type="Boolean">Boolean result - valid or invalid the "name" against the "constraint"</returns>
//region Initial check
if (name.typesAndValues.length === 0 || constraint.typesAndValues.length === 0) return true;
if (name.typesAndValues.length < constraint.typesAndValues.length) return false;
//endregion
//region Initial variables
var result = true;
var nameStart = 0;
//endregion
for (var i = 0; i < constraint.typesAndValues.length; i++) {
var localResult = false;
for (var j = nameStart; j < name.typesAndValues.length; j++) {
localResult = name.typesAndValues[j].isEqual(constraint.typesAndValues[i]);
if (name.typesAndValues[j].type === constraint.typesAndValues[i].type) result = result && localResult;
if (localResult === true) {
if (nameStart === 0 || nameStart === j) {
nameStart = j + 1;
break;
} else // Structure of "name" must be the same with "constraint"
return false;
}
}
if (localResult === false) return false;
}
return nameStart === 0 ? false : result;
};
compareIPAddress = function compareIPAddress(name, constraint) {
/// <summary>Compare two iPAddress values</summary>
/// <param name="name" type="in_window.org.pkijs.asn1.OCTETSTRING">iPAddress from name</param>
/// <param name="constraint" type="in_window.org.pkijs.asn1.OCTETSTRING">Constraint for iPAddress from name</param>
/// <returns type="Boolean">Boolean result - valid or invalid the "name" against the "constraint"</returns>
//region Common variables
var nameView = new Uint8Array(name.valueBlock.valueHex);
var constraintView = new Uint8Array(constraint.valueBlock.valueHex);
//endregion
//region Work with IPv4 addresses
if (nameView.length === 4 && constraintView.length === 8) {
for (var i = 0; i < 4; i++) {
if ((nameView[i] ^ constraintView[i]) & constraintView[i + 4]) return false;
}
return true;
}
//endregion
//region Work with IPv6 addresses
if (nameView.length === 16 && constraintView.length === 32) {
for (var _i9 = 0; _i9 < 16; _i9++) {
if ((nameView[_i9] ^ constraintView[_i9]) & constraintView[_i9 + 16]) return false;
}
return true;
}
//endregion
return false;
};
compareUniformResourceIdentifier = function compareUniformResourceIdentifier(name, constraint) {
/// <summary>Compare two uniformResourceIdentifier values</summary>
/// <param name="name" type="String">uniformResourceIdentifier from name</param>
/// <param name="constraint" type="String">Constraint for uniformResourceIdentifier from name</param>
/// <returns type="Boolean">Boolean result - valid or invalid the "name" against the "constraint"</returns>
//region Make a "string preparation" for both name and constrain
var namePrepared = (0, _common.stringPrep)(name);
var constraintPrepared = (0, _common.stringPrep)(constraint);
//endregion
//region Find out a major URI part to compare with
var ns = namePrepared.split("/");
var cs = constraintPrepared.split("/");
if (cs.length > 1) // Malformed constraint
return false;
if (ns.length > 1) // Full URI string
{
for (var i = 0; i < ns.length; i++) {
if (ns[i].length > 0 && ns[i].charAt(ns[i].length - 1) !== ":") {
var nsPort = ns[i].split(":");
namePrepared = nsPort[0];
break;
}
}
}
//endregion
var result = compareDNSName(namePrepared, constraintPrepared);
if (result) {
//region Make a "splitted" versions of "constraint" and "name"
var nameSplitted = namePrepared.split(".");
var constraintSplitted = constraintPrepared.split(".");
//endregion
if (constraintSplitted[0].length === 0) return true;
return nameSplitted.length === constraintSplitted.length;
}
return false;
};
compareRFC822Name = function compareRFC822Name(name, constraint) {
/// <summary>Compare two rfc822Name values</summary>
/// <param name="name" type="String">E-mail address from name</param>
/// <param name="constraint" type="String">Constraint for e-mail address from name</param>
/// <returns type="Boolean">Boolean result - valid or invalid the "name" against the "constraint"</returns>
//region Make a "string preparation" for both name and constrain
var namePrepared = (0, _common.stringPrep)(name);
var constraintPrepared = (0, _common.stringPrep)(constraint);
//endregion
//region Make a "splitted" versions of "constraint" and "name"
var nameSplitted = namePrepared.split("@");
var constraintSplitted = constraintPrepared.split("@");
//endregion
//region Splitted array length checking
if (nameSplitted.length === 0 || constraintSplitted.length === 0 || nameSplitted.length < constraintSplitted.length) return false;
//endregion
if (constraintSplitted.length === 1) {
var _result4 = compareDNSName(nameSplitted[1], constraintSplitted[0]);
if (_result4) {
//region Make a "splitted" versions of domain name from "constraint" and "name"
var ns = nameSplitted[1].split(".");
var cs = constraintSplitted[0].split(".");
//endregion
if (cs[0].length === 0) return true;
return ns.length === cs.length;
}
return false;
}
return namePrepared.localeCompare(constraintPrepared) === 0;
};
compareDNSName = function compareDNSName(name, constraint) {
/// <summary>Compare two dNSName values</summary>
/// <param name="name" type="String">DNS from name</param>
/// <param name="constraint" type="String">Constraint for DNS from name</param>
/// <returns type="Boolean">Boolean result - valid or invalid the "name" against the "constraint"</returns>
//region Make a "string preparation" for both name and constrain
var namePrepared = (0, _common.stringPrep)(name);
var constraintPrepared = (0, _common.stringPrep)(constraint);
//endregion
//region Make a "splitted" versions of "constraint" and "name"
var nameSplitted = namePrepared.split(".");
var constraintSplitted = constraintPrepared.split(".");
//endregion
//region Length calculation and additional check
var nameLen = nameSplitted.length;
var constrLen = constraintSplitted.length;
if (nameLen === 0 || constrLen === 0 || nameLen < constrLen) return false;
//endregion
//region Check that no part of "name" has zero length
for (var i = 0; i < nameLen; i++) {
if (nameSplitted[i].length === 0) return false;
}
//endregion
//region Check that no part of "constraint" has zero length
for (var _i7 = 0; _i7 < constrLen; _i7++) {
if (constraintSplitted[_i7].length === 0) {
if (_i7 === 0) {
if (constrLen === 1) return false;
continue;
}
return false;
}
}
//endregion
//region Check that "name" has a tail as "constraint"
for (var _i8 = 0; _i8 < constrLen; _i8++) {
if (constraintSplitted[constrLen - 1 - _i8].length === 0) continue;
if (nameSplitted[nameLen - 1 - _i8].localeCompare(constraintSplitted[constrLen - 1 - _i8]) !== 0) return false;
}
//endregion
return true;
};
//region Auxiliary functions for name constraints checking
_context8.prev = 5;
if (!(this.certs.length === 0)) {
_context8.next = 8;
break;
}
throw "Empty certificate array";
case 8:
//endregion
//region Get input variables
initialPolicySet = [];
initialPolicySet.push("2.5.29.32.0"); // "anyPolicy"
initialExplicitPolicy = false;
initialPolicyMappingInhibit = false;
initialInhibitPolicy = false;
initialPermittedSubtreesSet = []; // Array of "simpl.x509.GeneralSubtree"
initialExcludedSubtreesSet = []; // Array of "simpl.x509.GeneralSubtree"
initialRequiredNameForms = []; // Array of "simpl.x509.GeneralSubtree"
if ("initialPolicySet" in parameters) initialPolicySet = parameters.initialPolicySet;
if ("initialExplicitPolicy" in parameters) initialExplicitPolicy = parameters.initialExplicitPolicy;
if ("initialPolicyMappingInhibit" in parameters) initialPolicyMappingInhibit = parameters.initialPolicyMappingInhibit;
if ("initialInhibitPolicy" in parameters) initialInhibitPolicy = parameters.initialInhibitPolicy;
if ("initialPermittedSubtreesSet" in parameters) initialPermittedSubtreesSet = parameters.initialPermittedSubtreesSet;
if ("initialExcludedSubtreesSet" in parameters) initialExcludedSubtreesSet = parameters.initialExcludedSubtreesSet;
if ("initialRequiredNameForms" in parameters) initialRequiredNameForms = parameters.initialRequiredNameForms;
explicitPolicyIndicator = initialExplicitPolicy;
policyMappingInhibitIndicator = initialPolicyMappingInhibit;
inhibitAnyPolicyIndicator = initialInhibitPolicy;
pendingConstraints = new Array(3);
pendingConstraints[0] = false; // For "explicitPolicyPending"
pendingConstraints[1] = false; // For "policyMappingInhibitPending"
pendingConstraints[2] = false; // For "inhibitAnyPolicyPending"
explicitPolicyPending = 0;
policy