PHP WebShell
Текущая директория: /opt/BitGoJS/node_modules/isomorphic-webcrypto/src
Просмотр файла: webcrypto-liner.js
var liner = (function (exports) {
'use strict';
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
_defineProperty(target, key, source[key]);
});
}
return target;
}
class Debug {
static get enabled() {
return typeof self !== "undefined" && window.PV_WEBCRYPTO_LINER_LOG;
}
static log(message, ...optionalParams) {
if (this.enabled) {
console.log.apply(console, arguments);
}
}
static error(message, ...optionalParams) {
if (this.enabled) {
console.error.apply(console, arguments);
}
}
static info(message, ...optionalParams) {
if (this.enabled) {
console.info.apply(console, arguments);
}
}
static warn(message, ...optionalParams) {
if (this.enabled) {
console.warn.apply(console, arguments);
}
}
static trace(message, ...optionalParams) {
if (this.enabled) {
console.trace.apply(console, arguments);
}
}
}
// section modified by isomorphic-webcrypto build
const nativeCrypto = window.msCrypto || window.crypto || {};
let nativeSubtle = null;
try {
nativeSubtle = nativeCrypto.subtle || nativeCrypto.webkitSubtle;
} catch (err) {
console.warn("Cannot get subtle from crypto", err);
}
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
function __decorate(decorators, target, key, desc) {
var c = arguments.length,
r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __awaiter(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : new P(function (resolve) {
resolve(result.value);
}).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function PrepareBuffer(buffer) {
if (typeof Buffer !== "undefined") {
return new Uint8Array(buffer);
} else {
return new Uint8Array(buffer instanceof ArrayBuffer ? buffer : buffer.buffer);
}
}
class Convert {
static ToString(buffer, enc = "utf8") {
const buf = PrepareBuffer(buffer);
switch (enc.toLowerCase()) {
case "utf8":
return this.ToUtf8String(buf);
case "binary":
return this.ToBinary(buf);
case "hex":
return this.ToHex(buf);
case "base64":
return this.ToBase64(buf);
case "base64url":
return this.ToBase64Url(buf);
default:
throw new Error(`Unknown type of encoding '${enc}'`);
}
}
static FromString(str, enc = "utf8") {
switch (enc.toLowerCase()) {
case "utf8":
return this.FromUtf8String(str);
case "binary":
return this.FromBinary(str);
case "hex":
return this.FromHex(str);
case "base64":
return this.FromBase64(str);
case "base64url":
return this.FromBase64Url(str);
default:
throw new Error(`Unknown type of encoding '${enc}'`);
}
}
static ToBase64(buffer) {
const buf = PrepareBuffer(buffer);
if (typeof btoa !== "undefined") {
const binary = this.ToString(buf, "binary");
return btoa(binary);
} else {
return Buffer.from(buf).toString("base64");
}
}
static FromBase64(base64Text) {
base64Text = base64Text.replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "").replace(/\s/g, "");
if (typeof atob !== "undefined") {
return this.FromBinary(atob(base64Text));
} else {
return new Uint8Array(Buffer.from(base64Text, "base64")).buffer;
}
}
static FromBase64Url(base64url) {
return this.FromBase64(this.Base64Padding(base64url.replace(/\-/g, "+").replace(/\_/g, "/")));
}
static ToBase64Url(data) {
return this.ToBase64(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, "");
}
static FromUtf8String(text) {
const s = unescape(encodeURIComponent(text));
const uintArray = new Uint8Array(s.length);
for (let i = 0; i < s.length; i++) {
uintArray[i] = s.charCodeAt(i);
}
return uintArray.buffer;
}
static ToUtf8String(buffer) {
const buf = PrepareBuffer(buffer);
const encodedString = String.fromCharCode.apply(null, buf);
const decodedString = decodeURIComponent(escape(encodedString));
return decodedString;
}
static FromBinary(text) {
const stringLength = text.length;
const resultView = new Uint8Array(stringLength);
for (let i = 0; i < stringLength; i++) {
resultView[i] = text.charCodeAt(i);
}
return resultView.buffer;
}
static ToBinary(buffer) {
const buf = PrepareBuffer(buffer);
let resultString = "";
const len = buf.length;
for (let i = 0; i < len; i++) {
resultString = resultString + String.fromCharCode(buf[i]);
}
return resultString;
}
static ToHex(buffer) {
const buf = PrepareBuffer(buffer);
const splitter = "";
const res = [];
const len = buf.length;
for (let i = 0; i < len; i++) {
const char = buf[i].toString(16);
res.push(char.length === 1 ? "0" + char : char);
}
return res.join(splitter);
}
static FromHex(hexString) {
const res = new Uint8Array(hexString.length / 2);
for (let i = 0; i < hexString.length; i = i + 2) {
const c = hexString.slice(i, i + 2);
res[i / 2] = parseInt(c, 16);
}
return res.buffer;
}
static Base64Padding(base64) {
const padCount = 4 - base64.length % 4;
if (padCount < 4) {
for (let i = 0; i < padCount; i++) {
base64 += "=";
}
}
return base64;
}
}
/**
* Copyright (c) 2019, Peculiar Ventures, All rights reserved.
*/
class CryptoError extends Error {}
class AlgorithmError extends CryptoError {}
class UnsupportedOperationError extends CryptoError {
constructor(methodName) {
super(`Unsupported operation: ${methodName ? `${methodName}` : ""}`);
}
}
class OperationError extends CryptoError {}
class RequiredPropertyError extends CryptoError {
constructor(propName) {
super(`${propName}: Missing required property`);
}
}
class BufferSourceConverter {
static toArrayBuffer(data) {
if (data instanceof ArrayBuffer) {
return data;
}
if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
return new Uint8Array(data);
}
if (ArrayBuffer.isView(data)) {
return data.buffer;
}
throw new TypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView)'");
}
static toUint8Array(data) {
return new Uint8Array(this.toArrayBuffer(data));
}
static isBufferSource(data) {
return ArrayBuffer.isView(data) || data instanceof ArrayBuffer;
}
}
function isJWK(data) {
return typeof data === "object" && "kty" in data;
}
class ProviderCrypto {
digest(algorithm, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkDigest.apply(this, arguments);
return this.onDigest.apply(this, arguments);
});
}
checkDigest(algorithm, data) {
this.checkAlgorithmName(algorithm);
}
onDigest(algorithm, data) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("digest");
});
}
generateKey(algorithm, extractable, keyUsages) {
return __awaiter(this, arguments, void 0, function* () {
this.checkGenerateKey.apply(this, arguments);
return this.onGenerateKey.apply(this, arguments);
});
}
checkGenerateKey(algorithm, extractable, keyUsages) {
this.checkAlgorithmName(algorithm);
this.checkGenerateKeyParams(algorithm);
if (!(keyUsages && keyUsages.length)) {
throw new TypeError(`Usages cannot be empty when creating a key.`);
}
let allowedUsages;
if (Array.isArray(this.usages)) {
allowedUsages = this.usages;
} else {
allowedUsages = this.usages.privateKey.concat(this.usages.publicKey);
}
this.checkKeyUsages(keyUsages, allowedUsages);
}
checkGenerateKeyParams(algorithm) {}
onGenerateKey(algorithm, extractable, keyUsages) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("generateKey");
});
}
sign(algorithm, key, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkSign.apply(this, arguments);
return this.onSign.apply(this, arguments);
});
}
checkSign(algorithm, key, data) {
this.checkAlgorithmName(algorithm);
this.checkAlgorithmParams(algorithm);
this.checkCryptoKey(key, "sign");
}
onSign(algorithm, key, data) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("sign");
});
}
verify(algorithm, key, signature, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkVerify.apply(this, arguments);
return this.onVerify.apply(this, arguments);
});
}
checkVerify(algorithm, key, signature, data) {
this.checkAlgorithmName(algorithm);
this.checkAlgorithmParams(algorithm);
this.checkCryptoKey(key, "verify");
}
onVerify(algorithm, key, signature, data) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("verify");
});
}
encrypt(algorithm, key, data, options) {
return __awaiter(this, arguments, void 0, function* () {
this.checkEncrypt.apply(this, arguments);
return this.onEncrypt.apply(this, arguments);
});
}
checkEncrypt(algorithm, key, data, options = {}) {
this.checkAlgorithmName(algorithm);
this.checkAlgorithmParams(algorithm);
this.checkCryptoKey(key, options.keyUsage ? "encrypt" : void 0);
}
onEncrypt(algorithm, key, data) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("encrypt");
});
}
decrypt(algorithm, key, data, options) {
return __awaiter(this, arguments, void 0, function* () {
this.checkDecrypt.apply(this, arguments);
return this.onDecrypt.apply(this, arguments);
});
}
checkDecrypt(algorithm, key, data, options = {}) {
this.checkAlgorithmName(algorithm);
this.checkAlgorithmParams(algorithm);
this.checkCryptoKey(key, options.keyUsage ? "decrypt" : void 0);
}
onDecrypt(algorithm, key, data) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("decrypt");
});
}
deriveBits(algorithm, baseKey, length, options) {
return __awaiter(this, arguments, void 0, function* () {
this.checkDeriveBits.apply(this, arguments);
return this.onDeriveBits.apply(this, arguments);
});
}
checkDeriveBits(algorithm, baseKey, length, options = {}) {
this.checkAlgorithmName(algorithm);
this.checkAlgorithmParams(algorithm);
this.checkCryptoKey(baseKey, options.keyUsage ? "deriveBits" : void 0);
if (length % 8 !== 0) {
throw new OperationError("length: Is not multiple of 8");
}
}
onDeriveBits(algorithm, baseKey, length) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("deriveBits");
});
}
exportKey(format, key) {
return __awaiter(this, arguments, void 0, function* () {
this.checkExportKey.apply(this, arguments);
return this.onExportKey.apply(this, arguments);
});
}
checkExportKey(format, key) {
this.checkKeyFormat(format);
this.checkCryptoKey(key);
if (!key.extractable) {
throw new CryptoError("key: Is not extractable");
}
}
onExportKey(format, key) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("exportKey");
});
}
importKey(format, keyData, algorithm, extractable, keyUsages) {
return __awaiter(this, arguments, void 0, function* () {
this.checkImportKey.apply(this, arguments);
return this.onImportKey.apply(this, arguments);
});
}
checkImportKey(format, keyData, algorithm, extractable, keyUsages) {
this.checkKeyFormat(format);
this.checkKeyData(format, keyData);
this.checkAlgorithmName(algorithm);
this.checkImportParams(algorithm);
if (Array.isArray(this.usages)) {
this.checkKeyUsages(keyUsages, this.usages);
}
}
onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnsupportedOperationError("importKey");
});
}
checkAlgorithmName(algorithm) {
if (algorithm.name.toLowerCase() !== this.name.toLowerCase()) {
throw new AlgorithmError("Unrecognized name");
}
}
checkAlgorithmParams(algorithm) {}
checkDerivedKeyParams(algorithm) {}
checkKeyUsages(usages, allowed) {
for (const usage of usages) {
if (allowed.indexOf(usage) === -1) {
throw new TypeError("Cannot create a key using the specified key usages");
}
}
}
checkCryptoKey(key, keyUsage) {
this.checkAlgorithmName(key.algorithm);
if (keyUsage && key.usages.indexOf(keyUsage) === -1) {
throw new CryptoError(`key does not match that of operation`);
}
}
checkRequiredProperty(data, propName) {
if (!(propName in data)) {
throw new RequiredPropertyError(propName);
}
}
checkHashAlgorithm(algorithm, hashAlgorithms) {
for (const item of hashAlgorithms) {
if (item.toLowerCase() === algorithm.name.toLowerCase()) {
return;
}
}
throw new OperationError(`hash: Must be one of ${hashAlgorithms.join(", ")}`);
}
checkImportParams(algorithm) {}
checkKeyFormat(format) {
switch (format) {
case "raw":
case "pkcs8":
case "spki":
case "jwk":
break;
default:
throw new TypeError("format: Is invalid value. Must be 'jwk', 'raw', 'spki', or 'pkcs8'");
}
}
checkKeyData(format, keyData) {
if (!keyData) {
throw new TypeError("keyData: Cannot be empty on empty on key importing");
}
if (format === "jwk") {
if (!isJWK(keyData)) {
throw new TypeError("keyData: Is not JsonWebToken");
}
} else if (!BufferSourceConverter.isBufferSource(keyData)) {
throw new TypeError("keyData: Is not ArrayBufferView or ArrrayBuffer");
}
}
prepareData(data) {
return BufferSourceConverter.toArrayBuffer(data);
}
}
class AesProvider extends ProviderCrypto {
checkGenerateKeyParams(algorithm) {
this.checkRequiredProperty(algorithm, "length");
if (typeof algorithm.length !== "number") {
throw new TypeError("length: Is not of type Number");
}
switch (algorithm.length) {
case 128:
case 192:
case 256:
break;
default:
throw new TypeError("length: Must be 128, 192, or 256");
}
}
checkDerivedKeyParams(algorithm) {
this.checkGenerateKeyParams(algorithm);
}
}
class AesCbcProvider extends AesProvider {
constructor() {
super(...arguments);
this.name = "AES-CBC";
this.usages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"];
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "iv");
if (!(algorithm.iv instanceof ArrayBuffer || ArrayBuffer.isView(algorithm.iv))) {
throw new TypeError("iv: Is not of type '(ArrayBuffer or ArrayBufferView)'");
}
if (algorithm.iv.byteLength !== 16) {
throw new TypeError("iv: Must have length 16 bytes");
}
}
}
class AesCtrProvider extends AesProvider {
constructor() {
super(...arguments);
this.name = "AES-CTR";
this.usages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"];
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "counter");
if (!(algorithm.counter instanceof ArrayBuffer || ArrayBuffer.isView(algorithm.counter))) {
throw new TypeError("counter: Is not of type '(ArrayBuffer or ArrayBufferView)'");
}
if (algorithm.counter.byteLength !== 16) {
throw new TypeError("iv: Must have length 16 bytes");
}
this.checkRequiredProperty(algorithm, "length");
if (typeof algorithm.length !== "number") {
throw new TypeError("length: Is not a Number");
}
if (algorithm.length < 1) {
throw new OperationError("length: Must be more than 0");
}
}
}
class AesEcbProvider extends AesProvider {
constructor() {
super(...arguments);
this.name = "AES-ECB";
this.usages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"];
}
}
class AesGcmProvider extends AesProvider {
constructor() {
super(...arguments);
this.name = "AES-GCM";
this.usages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"];
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "iv");
if (!(algorithm.iv instanceof ArrayBuffer || ArrayBuffer.isView(algorithm.iv))) {
throw new TypeError("iv: Is not of type '(ArrayBuffer or ArrayBufferView)'");
}
if (algorithm.iv.byteLength < 1) {
throw new OperationError("iv: Must have length more than 0 and less than 2^64 - 1");
}
if (!("tagLength" in algorithm)) {
algorithm.tagLength = 128;
}
switch (algorithm.tagLength) {
case 32:
case 64:
case 96:
case 104:
case 112:
case 120:
case 128:
break;
default:
throw new OperationError("tagLength: Must be one of 32, 64, 96, 104, 112, 120 or 128");
}
}
}
class AesKwProvider extends AesProvider {
constructor() {
super(...arguments);
this.name = "AES-KW";
this.usages = ["wrapKey", "unwrapKey"];
}
}
class DesProvider extends ProviderCrypto {
constructor() {
super(...arguments);
this.usages = ["encrypt", "decrypt", "wrapKey", "unwrapKey"];
}
checkAlgorithmParams(algorithm) {
if (this.ivSize) {
this.checkRequiredProperty(algorithm, "iv");
if (!(algorithm.iv instanceof ArrayBuffer || ArrayBuffer.isView(algorithm.iv))) {
throw new TypeError("iv: Is not of type '(ArrayBuffer or ArrayBufferView)'");
}
if (algorithm.iv.byteLength !== this.ivSize) {
throw new TypeError(`iv: Must have length ${this.ivSize} bytes`);
}
}
}
checkGenerateKeyParams(algorithm) {
this.checkRequiredProperty(algorithm, "length");
if (typeof algorithm.length !== "number") {
throw new TypeError("length: Is not of type Number");
}
if (algorithm.length !== this.keySizeBits) {
throw new OperationError(`algorith.length: Must be ${this.keySizeBits}`);
}
}
checkDerivedKeyParams(algorithm) {
this.checkGenerateKeyParams(algorithm);
}
}
class RsaProvider extends ProviderCrypto {
constructor() {
super(...arguments);
this.hashAlgorithms = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"];
}
checkGenerateKeyParams(algorithm) {
this.checkRequiredProperty(algorithm, "hash");
this.checkHashAlgorithm(algorithm.hash, this.hashAlgorithms);
this.checkRequiredProperty(algorithm, "publicExponent");
if (!(algorithm.publicExponent && algorithm.publicExponent instanceof Uint8Array)) {
throw new TypeError("publicExponent: Missing or not a Uint8Array");
}
const publicExponent = Convert.ToBase64(algorithm.publicExponent);
if (!(publicExponent === "Aw==" || publicExponent === "AQAB")) {
throw new TypeError("publicExponent: Must be [3] or [1,0,1]");
}
this.checkRequiredProperty(algorithm, "modulusLength");
switch (algorithm.modulusLength) {
case 1024:
case 2048:
case 4096:
break;
default:
throw new TypeError("modulusLength: Must be 1024, 2048, or 4096");
}
}
checkImportParams(algorithm) {
this.checkRequiredProperty(algorithm, "hash");
this.checkHashAlgorithm(algorithm.hash, this.hashAlgorithms);
}
}
class RsaSsaProvider extends RsaProvider {
constructor() {
super(...arguments);
this.name = "RSASSA-PKCS1-v1_5";
this.usages = {
privateKey: ["sign"],
publicKey: ["verify"]
};
}
}
class RsaPssProvider extends RsaProvider {
constructor() {
super(...arguments);
this.name = "RSA-PSS";
this.usages = {
privateKey: ["sign"],
publicKey: ["verify"]
};
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "saltLength");
if (typeof algorithm.saltLength !== "number") {
throw new TypeError("saltLength: Is not a Number");
}
if (algorithm.saltLength < 1) {
throw new RangeError("saltLength: Must be more than 0");
}
}
}
class RsaOaepProvider extends RsaProvider {
constructor() {
super(...arguments);
this.name = "RSA-OAEP";
this.usages = {
privateKey: ["decrypt", "unwrapKey"],
publicKey: ["encrypt", "wrapKey"]
};
}
checkAlgorithmParams(algorithm) {
if (algorithm.label && !(algorithm.label instanceof ArrayBuffer || ArrayBuffer.isView(algorithm.label))) {
throw new TypeError("label: Is not of type '(ArrayBuffer or ArrayBufferView)'");
}
}
}
class EllipticProvider extends ProviderCrypto {
checkGenerateKeyParams(algorithm) {
this.checkRequiredProperty(algorithm, "namedCurve");
this.checkNamedCurve(algorithm.namedCurve);
}
checkNamedCurve(namedCurve) {
for (const item of this.namedCurves) {
if (item.toLowerCase() === namedCurve.toLowerCase()) {
return;
}
}
throw new OperationError(`namedCurve: Must be one of ${this.namedCurves.join(", ")}`);
}
}
class EcdsaProvider extends EllipticProvider {
constructor() {
super(...arguments);
this.name = "ECDSA";
this.hashAlgorithms = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"];
this.usages = {
privateKey: ["sign"],
publicKey: ["verify"]
};
this.namedCurves = ["P-256", "P-384", "P-521", "K-256"];
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "hash");
this.checkHashAlgorithm(algorithm.hash, this.hashAlgorithms);
}
}
const KEY_TYPES = ["secret", "private", "public"];
class CryptoKey {
static create(algorithm, type, extractable, usages) {
const key = new this();
key.algorithm = algorithm;
key.type = type;
key.extractable = extractable;
key.usages = usages;
return key;
}
static isKeyType(data) {
return KEY_TYPES.indexOf(data) !== -1;
}
}
class EcdhProvider extends EllipticProvider {
constructor() {
super(...arguments);
this.name = "ECDH";
this.usages = {
privateKey: ["deriveBits", "deriveKey"],
publicKey: []
};
this.namedCurves = ["P-256", "P-384", "P-521"];
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "public");
if (!(algorithm.public instanceof CryptoKey)) {
throw new TypeError("public: Is not a CryptoKey");
}
if (algorithm.public.type !== "public") {
throw new OperationError("public: Is not a public key");
}
if (algorithm.public.algorithm.name !== this.name) {
throw new OperationError(`public: Is not ${this.name} key`);
}
}
}
class Pbkdf2Provider extends ProviderCrypto {
constructor() {
super(...arguments);
this.name = "PBKDF2";
this.hashAlgorithms = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"];
this.usages = ["deriveBits", "deriveKey"];
}
checkAlgorithmParams(algorithm) {
this.checkRequiredProperty(algorithm, "hash");
this.checkHashAlgorithm(algorithm.hash, this.hashAlgorithms);
this.checkRequiredProperty(algorithm, "salt");
if (!(algorithm.salt instanceof ArrayBuffer || ArrayBuffer.isView(algorithm.salt))) {
throw new TypeError("salt: Is not of type '(ArrayBuffer or ArrayBufferView)'");
}
this.checkRequiredProperty(algorithm, "iterations");
if (typeof algorithm.iterations !== "number") {
throw new TypeError("iterations: Is not a Number");
}
if (algorithm.iterations < 1) {
throw new TypeError("iterations: Is less than 1");
}
}
checkImportKey(format, keyData, algorithm, extractable, keyUsages) {
super.checkImportKey(format, keyData, algorithm, extractable, keyUsages);
if (extractable) {
throw new SyntaxError("extractable: Must be False");
}
}
}
class Crypto {}
class ProviderStorage {
constructor() {
this.items = {};
}
get(algorithmName) {
return this.items[algorithmName.toLowerCase()] || null;
}
set(provider) {
this.items[provider.name.toLowerCase()] = provider;
}
removeAt(algorithmName) {
const provider = this.get(algorithmName.toLowerCase());
if (provider) {
delete this.items[algorithmName];
}
return provider;
}
has(name) {
return !!this.get(name);
}
get length() {
return Object.keys(this.items).length;
}
get algorithms() {
const algorithms = [];
for (const key in this.items) {
const provider = this.items[key];
algorithms.push(provider.name);
}
return algorithms.sort();
}
}
class SubtleCrypto {
constructor() {
this.providers = new ProviderStorage();
}
static isHashedAlgorithm(data) {
return data instanceof Object && "name" in data && "hash" in data;
}
digest(algorithm, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 2, "digest");
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(data);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.digest(preparedAlgorithm, preparedData);
return result;
});
}
generateKey(algorithm, extractable, keyUsages) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 3, "generateKey");
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.generateKey(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), extractable, keyUsages);
return result;
});
}
sign(algorithm, key, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 3, "sign");
this.checkCryptoKey(key);
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(data);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.sign(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), key, preparedData);
return result;
});
}
verify(algorithm, key, signature, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 4, "verify");
this.checkCryptoKey(key);
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(data);
const preparedSignature = BufferSourceConverter.toArrayBuffer(signature);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.verify(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), key, preparedSignature, preparedData);
return result;
});
}
encrypt(algorithm, key, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 3, "encrypt");
this.checkCryptoKey(key);
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(data);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.encrypt(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), key, preparedData, {
keyUsage: true
});
return result;
});
}
decrypt(algorithm, key, data) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 3, "decrypt");
this.checkCryptoKey(key);
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(data);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.decrypt(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), key, preparedData, {
keyUsage: true
});
return result;
});
}
deriveBits(algorithm, baseKey, length) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 3, "deriveBits");
this.checkCryptoKey(baseKey);
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const provider = this.getProvider(preparedAlgorithm.name);
const result = yield provider.deriveBits(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), baseKey, length, {
keyUsage: true
});
return result;
});
}
deriveKey(algorithm, baseKey, derivedKeyType, extractable, keyUsages) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 5, "deriveKey");
const preparedDerivedKeyType = this.prepareAlgorithm(derivedKeyType);
const importProvider = this.getProvider(preparedDerivedKeyType.name);
importProvider.checkDerivedKeyParams(preparedDerivedKeyType);
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const provider = this.getProvider(preparedAlgorithm.name);
provider.checkCryptoKey(baseKey, "deriveKey");
const derivedBits = yield provider.deriveBits(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), baseKey, derivedKeyType.length, {
keyUsage: false
});
return this.importKey("raw", derivedBits, derivedKeyType, extractable, keyUsages);
});
}
exportKey(format, key) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 2, "exportKey");
this.checkCryptoKey(key);
const provider = this.getProvider(key.algorithm.name);
const result = yield provider.exportKey(format, key);
return result;
});
}
importKey(format, keyData, algorithm, extractable, keyUsages) {
return __awaiter(this, arguments, void 0, function* () {
this.checkRequiredArguments(arguments, 5, "importKey");
const preparedAlgorithm = this.prepareAlgorithm(algorithm);
const provider = this.getProvider(preparedAlgorithm.name);
if (["pkcs8", "spki", "raw"].indexOf(format) !== -1) {
const preparedData = BufferSourceConverter.toArrayBuffer(keyData);
return provider.importKey(format, preparedData, Object.assign({}, preparedAlgorithm, {
name: provider.name
}), extractable, keyUsages);
} else {
if (!keyData.kty) {
throw new TypeError("keyData: Is not JSON");
}
}
return provider.importKey(format, keyData, Object.assign({}, preparedAlgorithm, {
name: provider.name
}), extractable, keyUsages);
});
}
wrapKey(format, key, wrappingKey, wrapAlgorithm) {
return __awaiter(this, void 0, void 0, function* () {
let keyData = yield this.exportKey(format, key);
if (format === "jwk") {
const json = JSON.stringify(keyData);
keyData = Convert.FromUtf8String(json);
}
const preparedAlgorithm = this.prepareAlgorithm(wrapAlgorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(keyData);
const provider = this.getProvider(preparedAlgorithm.name);
return provider.encrypt(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), wrappingKey, preparedData, {
keyUsage: false
});
});
}
unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) {
return __awaiter(this, void 0, void 0, function* () {
const preparedAlgorithm = this.prepareAlgorithm(unwrapAlgorithm);
const preparedData = BufferSourceConverter.toArrayBuffer(wrappedKey);
const provider = this.getProvider(preparedAlgorithm.name);
let keyData = yield provider.decrypt(Object.assign({}, preparedAlgorithm, {
name: provider.name
}), unwrappingKey, preparedData, {
keyUsage: false
});
if (format === "jwk") {
try {
keyData = JSON.parse(Convert.ToUtf8String(keyData));
} catch (e) {
const error = new TypeError("wrappedKey: Is not a JSON");
error.internal = e;
throw error;
}
}
return this.importKey(format, keyData, unwrappedKeyAlgorithm, extractable, keyUsages);
});
}
checkRequiredArguments(args, size, methodName) {
if (args.length !== size) {
throw new TypeError(`Failed to execute '${methodName}' on 'SubtleCrypto': ${size} arguments required, but only ${args.length} present`);
}
}
prepareAlgorithm(algorithm) {
if (typeof algorithm === "string") {
return {
name: algorithm
};
}
if (SubtleCrypto.isHashedAlgorithm(algorithm)) {
const preparedAlgorithm = Object.assign({}, algorithm);
preparedAlgorithm.hash = this.prepareAlgorithm(algorithm.hash);
return preparedAlgorithm;
}
return Object.assign({}, algorithm);
}
getProvider(name) {
const provider = this.providers.get(name);
if (!provider) {
throw new AlgorithmError("Unrecognized name");
}
return provider;
}
checkCryptoKey(key) {
if (!(key instanceof CryptoKey)) {
throw new TypeError(`Key is not of type 'CryptoKey'`);
}
}
}
function unwrapExports(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x.default : x;
}
function createCommonjsModule(fn, module) {
return module = {
exports: {}
}, fn(module, module.exports), module.exports;
} //**************************************************************************************
/**
* Making UTC date from local date
* @param {Date} date Date to convert from
* @returns {Date}
*/
function getUTCDate(date) {
// noinspection NestedFunctionCallJS, MagicNumberJS
return new Date(date.getTime() + date.getTimezoneOffset() * 60000);
} //**************************************************************************************
// noinspection FunctionWithMultipleReturnPointsJS
/**
* Get value for input parameters, or set a default value
* @param {Object} parameters
* @param {string} name
* @param defaultValue
*/
function getParametersValue(parameters, name, defaultValue) {
// noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
if (parameters instanceof Object === false) return defaultValue; // noinspection NonBlockStatementBodyJS
if (name in parameters) return parameters[name];
return defaultValue;
} //**************************************************************************************
/**
* Converts "ArrayBuffer" into a hexdecimal string
* @param {ArrayBuffer} inputBuffer
* @param {number} [inputOffset=0]
* @param {number} [inputLength=inputBuffer.byteLength]
* @param {boolean} [insertSpace=false]
* @returns {string}
*/
function bufferToHexCodes(inputBuffer, inputOffset = 0, inputLength = inputBuffer.byteLength - inputOffset, insertSpace = false) {
let result = "";
for (const item of new Uint8Array(inputBuffer, inputOffset, inputLength)) {
// noinspection ChainedFunctionCallJS
const str = item.toString(16).toUpperCase(); // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
if (str.length === 1) result += "0";
result += str; // noinspection NonBlockStatementBodyJS
if (insertSpace) result += " ";
}
return result.trim();
} //**************************************************************************************
// noinspection JSValidateJSDoc, FunctionWithMultipleReturnPointsJS
/**
* Check input "ArrayBuffer" for common functions
* @param {LocalBaseBlock} baseBlock
* @param {ArrayBuffer} inputBuffer
* @param {number} inputOffset
* @param {number} inputLength
* @returns {boolean}
*/
function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) {
// noinspection ConstantOnRightSideOfComparisonJS
if (inputBuffer instanceof ArrayBuffer === false) {
// noinspection JSUndefinedPropertyAssignment
baseBlock.error = "Wrong parameter: inputBuffer must be \"ArrayBuffer\"";
return false;
} // noinspection ConstantOnRightSideOfComparisonJS
if (inputBuffer.byteLength === 0) {
// noinspection JSUndefinedPropertyAssignment
baseBlock.error = "Wrong parameter: inputBuffer has zero length";
return false;
} // noinspection ConstantOnRightSideOfComparisonJS
if (inputOffset < 0) {
// noinspection JSUndefinedPropertyAssignment
baseBlock.error = "Wrong parameter: inputOffset less than zero";
return false;
} // noinspection ConstantOnRightSideOfComparisonJS
if (inputLength < 0) {
// noinspection JSUndefinedPropertyAssignment
baseBlock.error = "Wrong parameter: inputLength less than zero";
return false;
} // noinspection ConstantOnRightSideOfComparisonJS
if (inputBuffer.byteLength - inputOffset - inputLength < 0) {
// noinspection JSUndefinedPropertyAssignment
baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
return false;
}
return true;
} //**************************************************************************************
// noinspection FunctionWithMultipleReturnPointsJS
/**
* Convert number from 2^base to 2^10
* @param {Uint8Array} inputBuffer
* @param {number} inputBase
* @returns {number}
*/
function utilFromBase(inputBuffer, inputBase) {
let result = 0; // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
if (inputBuffer.length === 1) return inputBuffer[0]; // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
for (let i = inputBuffer.length - 1; i >= 0; i--) result += inputBuffer[inputBuffer.length - 1 - i] * Math.pow(2, inputBase * i);
return result;
} //**************************************************************************************
// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS
/**
* Convert number from 2^10 to 2^base
* @param {!number} value The number to convert
* @param {!number} base The base for 2^base
* @param {number} [reserved=0] Pre-defined number of bytes in output array (-1 = limited by function itself)
* @returns {ArrayBuffer}
*/
function utilToBase(value, base, reserved = -1) {
const internalReserved = reserved;
let internalValue = value;
let result = 0;
let biggest = Math.pow(2, base); // noinspection ConstantOnRightSideOfComparisonJS
for (let i = 1; i < 8; i++) {
if (value < biggest) {
let retBuf; // noinspection ConstantOnRightSideOfComparisonJS
if (internalReserved < 0) {
retBuf = new ArrayBuffer(i);
result = i;
} else {
// noinspection NonBlockStatementBodyJS
if (internalReserved < i) return new ArrayBuffer(0);
retBuf = new ArrayBuffer(internalReserved);
result = internalReserved;
}
const retView = new Uint8Array(retBuf); // noinspection ConstantOnRightSideOfComparisonJS
for (let j = i - 1; j >= 0; j--) {
const basis = Math.pow(2, j * base);
retView[result - j - 1] = Math.floor(internalValue / basis);
internalValue -= retView[result - j - 1] * basis;
}
return retBuf;
}
biggest *= Math.pow(2, base);
}
return new ArrayBuffer(0);
} //**************************************************************************************
// noinspection FunctionWithMultipleLoopsJS
/**
* Concatenate two ArrayBuffers
* @param {...ArrayBuffer} buffers Set of ArrayBuffer
*/
function utilConcatBuf(...buffers) {
//region Initial variables
let outputLength = 0;
let prevLength = 0; //endregion
//region Calculate output length
// noinspection NonBlockStatementBodyJS
for (const buffer of buffers) outputLength += buffer.byteLength; //endregion
const retBuf = new ArrayBuffer(outputLength);
const retView = new Uint8Array(retBuf);
for (const buffer of buffers) {
// noinspection NestedFunctionCallJS
retView.set(new Uint8Array(buffer), prevLength);
prevLength += buffer.byteLength;
}
return retBuf;
} //**************************************************************************************
// noinspection FunctionWithMultipleLoopsJS
/**
* Concatenate two Uint8Array
* @param {...Uint8Array} views Set of Uint8Array
*/
function utilConcatView(...views) {
//region Initial variables
let outputLength = 0;
let prevLength = 0; //endregion
//region Calculate output length
// noinspection NonBlockStatementBodyJS
for (const view of views) outputLength += view.length; //endregion
const retBuf = new ArrayBuffer(outputLength);
const retView = new Uint8Array(retBuf);
for (const view of views) {
retView.set(view, prevLength);
prevLength += view.length;
}
return retView;
} //**************************************************************************************
// noinspection FunctionWithMultipleLoopsJS
/**
* Decoding of "two complement" values
* The function must be called in scope of instance of "hexBlock" class ("valueHex" and "warnings" properties must be present)
* @returns {number}
*/
function utilDecodeTC() {
const buf = new Uint8Array(this.valueHex); // noinspection ConstantOnRightSideOfComparisonJS
if (this.valueHex.byteLength >= 2) {
//noinspection JSBitwiseOperatorUsage, ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
const condition1 = buf[0] === 0xFF && buf[1] & 0x80; // noinspection ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
const condition2 = buf[0] === 0x00 && (buf[1] & 0x80) === 0x00; // noinspection NonBlockStatementBodyJS
if (condition1 || condition2) this.warnings.push("Needlessly long format");
} //region Create big part of the integer
const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength);
const bigIntView = new Uint8Array(bigIntBuffer); // noinspection NonBlockStatementBodyJS
for (let i = 0; i < this.valueHex.byteLength; i++) bigIntView[i] = 0; // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS
bigIntView[0] = buf[0] & 0x80; // mask only the biggest bit
const bigInt = utilFromBase(bigIntView, 8); //endregion
//region Create small part of the integer
const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength);
const smallIntView = new Uint8Array(smallIntBuffer); // noinspection NonBlockStatementBodyJS
for (let j = 0; j < this.valueHex.byteLength; j++) smallIntView[j] = buf[j]; // noinspection MagicNumberJS
smallIntView[0] &= 0x7F; // mask biggest bit
const smallInt = utilFromBase(smallIntView, 8); //endregion
return smallInt - bigInt;
} //**************************************************************************************
// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS
/**
* Encode integer value to "two complement" format
* @param {number} value Value to encode
* @returns {ArrayBuffer}
*/
function utilEncodeTC(value) {
// noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS
const modValue = value < 0 ? value * -1 : value;
let bigInt = 128; // noinspection ConstantOnRightSideOfComparisonJS
for (let i = 1; i < 8; i++) {
if (modValue <= bigInt) {
// noinspection ConstantOnRightSideOfComparisonJS
if (value < 0) {
const smallInt = bigInt - modValue;
const retBuf = utilToBase(smallInt, 8, i);
const retView = new Uint8Array(retBuf); // noinspection MagicNumberJS
retView[0] |= 0x80;
return retBuf;
}
let retBuf = utilToBase(modValue, 8, i);
let retView = new Uint8Array(retBuf); //noinspection JSBitwiseOperatorUsage, MagicNumberJS, NonShortCircuitBooleanExpressionJS
if (retView[0] & 0x80) {
//noinspection JSCheckFunctionSignatures
const tempBuf = retBuf.slice(0);
const tempView = new Uint8Array(tempBuf);
retBuf = new ArrayBuffer(retBuf.byteLength + 1); // noinspection ReuseOfLocalVariableJS
retView = new Uint8Array(retBuf); // noinspection NonBlockStatementBodyJS
for (let k = 0; k < tempBuf.byteLength; k++) retView[k + 1] = tempView[k]; // noinspection MagicNumberJS
retView[0] = 0x00;
}
return retBuf;
}
bigInt *= Math.pow(2, 8);
}
return new ArrayBuffer(0);
} //**************************************************************************************
// noinspection FunctionWithMultipleReturnPointsJS, ParameterNamingConventionJS
/**
* Compare two array buffers
* @param {!ArrayBuffer} inputBuffer1
* @param {!ArrayBuffer} inputBuffer2
* @returns {boolean}
*/
function isEqualBuffer(inputBuffer1, inputBuffer2) {
// noinspection NonBlockStatementBodyJS
if (inputBuffer1.byteLength !== inputBuffer2.byteLength) return false; // noinspection LocalVariableNamingConventionJS
const view1 = new Uint8Array(inputBuffer1); // noinspection LocalVariableNamingConventionJS
const view2 = new Uint8Array(inputBuffer2);
for (let i = 0; i < view1.length; i++) {
// noinspection NonBlockStatementBodyJS
if (view1[i] !== view2[i]) return false;
}
return true;
} //**************************************************************************************
// noinspection FunctionWithMultipleReturnPointsJS
/**
* Pad input number with leade "0" if needed
* @returns {string}
* @param {number} inputNumber
* @param {number} fullLength
*/
function padNumber(inputNumber, fullLength) {
const str = inputNumber.toString(10); // noinspection NonBlockStatementBodyJS
if (fullLength < str.length) return "";
const dif = fullLength - str.length;
const padding = new Array(dif); // noinspection NonBlockStatementBodyJS
for (let i = 0; i < dif; i++) padding[i] = "0";
const paddingString = padding.join("");
return paddingString.concat(str);
} //**************************************************************************************
const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; //**************************************************************************************
// noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS, FunctionNamingConventionJS
/**
* Encode string into BASE64 (or "base64url")
* @param {string} input
* @param {boolean} useUrlTemplate If "true" then output would be encoded using "base64url"
* @param {boolean} skipPadding Skip BASE-64 padding or not
* @param {boolean} skipLeadingZeros Skip leading zeros in input data or not
* @returns {string}
*/
function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) {
let i = 0; // noinspection LocalVariableNamingConventionJS
let flag1 = 0; // noinspection LocalVariableNamingConventionJS
let flag2 = 0;
let output = ""; // noinspection ConditionalExpressionJS
const template = useUrlTemplate ? base64UrlTemplate : base64Template;
if (skipLeadingZeros) {
let nonZeroPosition = 0;
for (let i = 0; i < input.length; i++) {
// noinspection ConstantOnRightSideOfComparisonJS
if (input.charCodeAt(i) !== 0) {
nonZeroPosition = i; // noinspection BreakStatementJS
break;
}
} // noinspection AssignmentToFunctionParameterJS
input = input.slice(nonZeroPosition);
}
while (i < input.length) {
// noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
const chr1 = input.charCodeAt(i++); // noinspection NonBlockStatementBodyJS
if (i >= input.length) flag1 = 1; // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
const chr2 = input.charCodeAt(i++); // noinspection NonBlockStatementBodyJS
if (i >= input.length) flag2 = 1; // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
const chr3 = input.charCodeAt(i++); // noinspection LocalVariableNamingConventionJS
const enc1 = chr1 >> 2; // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
const enc2 = (chr1 & 0x03) << 4 | chr2 >> 4; // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
let enc3 = (chr2 & 0x0F) << 2 | chr3 >> 6; // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
let enc4 = chr3 & 0x3F; // noinspection ConstantOnRightSideOfComparisonJS
if (flag1 === 1) {
// noinspection NestedAssignmentJS, AssignmentResultUsedJS, MagicNumberJS
enc3 = enc4 = 64;
} else {
// noinspection ConstantOnRightSideOfComparisonJS
if (flag2 === 1) {
// noinspection MagicNumberJS
enc4 = 64;
}
} // noinspection NonBlockStatementBodyJS
if (skipPadding) {
// noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
if (enc3 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}`;else {
// noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
if (enc4 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`;else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`;
}
} else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`;
}
return output;
} //**************************************************************************************
// noinspection FunctionWithMoreThanThreeNegationsJS, FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionNamingConventionJS
/**
* Decode string from BASE64 (or "base64url")
* @param {string} input
* @param {boolean} [useUrlTemplate=false] If "true" then output would be encoded using "base64url"
* @param {boolean} [cutTailZeros=false] If "true" then cut tailing zeroz from function result
* @returns {string}
*/
function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) {
// noinspection ConditionalExpressionJS
const template = useUrlTemplate ? base64UrlTemplate : base64Template; //region Aux functions
// noinspection FunctionWithMultipleReturnPointsJS, NestedFunctionJS
function indexof(toSearch) {
// noinspection ConstantOnRightSideOfComparisonJS, MagicNumberJS
for (let i = 0; i < 64; i++) {
// noinspection NonBlockStatementBodyJS
if (template.charAt(i) === toSearch) return i;
} // noinspection MagicNumberJS
return 64;
} // noinspection NestedFunctionJS
function test(incoming) {
// noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS, MagicNumberJS
return incoming === 64 ? 0x00 : incoming;
} //endregion
let i = 0;
let output = "";
while (i < input.length) {
// noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
const enc1 = indexof(input.charAt(i++)); // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS
const enc2 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS
const enc3 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS
const enc4 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); // noinspection LocalVariableNamingConventionJS, NonShortCircuitBooleanExpressionJS
const chr1 = test(enc1) << 2 | test(enc2) >> 4; // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
const chr2 = (test(enc2) & 0x0F) << 4 | test(enc3) >> 2; // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
const chr3 = (test(enc3) & 0x03) << 6 | test(enc4);
output += String.fromCharCode(chr1); // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
if (enc3 !== 64) output += String.fromCharCode(chr2); // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
if (enc4 !== 64) output += String.fromCharCode(chr3);
}
if (cutTailZeros) {
const outputLength = output.length;
let nonZeroStart = -1; // noinspection ConstantOnRightSideOfComparisonJS
for (let i = outputLength - 1; i >= 0; i--) {
// noinspection ConstantOnRightSideOfComparisonJS
if (output.charCodeAt(i) !== 0) {
nonZeroStart = i; // noinspection BreakStatementJS
break;
}
} // noinspection NonBlockStatementBodyJS, NegatedIfStatementJS
if (nonZeroStart !== -1) output = output.slice(0, nonZeroStart + 1);else output = "";
}
return output;
} //**************************************************************************************
function arrayBufferToString(buffer) {
let resultString = "";
const view = new Uint8Array(buffer); // noinspection NonBlockStatementBodyJS
for (const element of view) resultString += String.fromCharCode(element);
return resultString;
} //**************************************************************************************
function stringToArrayBuffer(str) {
const stringLength = str.length;
const resultBuffer = new ArrayBuffer(stringLength);
const resultView = new Uint8Array(resultBuffer); // noinspection NonBlockStatementBodyJS
for (let i = 0; i < stringLength; i++) resultView[i] = str.charCodeAt(i);
return resultBuffer;
} //**************************************************************************************
const log2 = Math.log(2); //**************************************************************************************
// noinspection FunctionNamingConventionJS
/**
* Get nearest to input length power of 2
* @param {number} length Current length of existing array
* @returns {number}
*/
function nearestPowerOf2(length) {
const base = Math.log(length) / log2;
const floor = Math.floor(base);
const round = Math.round(base); // noinspection ConditionalExpressionJS
return floor === round ? floor : round;
} //**************************************************************************************
/**
* Delete properties by name from specified object
* @param {Object} object Object to delete properties from
* @param {Array.<string>} propsArray Array of properties names
*/
function clearProps(object, propsArray) {
for (const prop of propsArray) delete object[prop];
} //**************************************************************************************
var utils =
/*#__PURE__*/
Object.freeze({
getUTCDate: getUTCDate,
getParametersValue: getParametersValue,
bufferToHexCodes: bufferToHexCodes,
checkBufferParams: checkBufferParams,
utilFromBase: utilFromBase,
utilToBase: utilToBase,
utilConcatBuf: utilConcatBuf,
utilConcatView: utilConcatView,
utilDecodeTC: utilDecodeTC,
utilEncodeTC: utilEncodeTC,
isEqualBuffer: isEqualBuffer,
padNumber: padNumber,
toBase64: toBase64,
fromBase64: fromBase64,
arrayBufferToString: arrayBufferToString,
stringToArrayBuffer: stringToArrayBuffer,
nearestPowerOf2: nearestPowerOf2,
clearProps: clearProps
});
var asn1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RawData = exports.Repeated = exports.Any = exports.Choice = exports.TIME = exports.Duration = exports.DateTime = exports.TimeOfDay = exports.DATE = exports.GeneralizedTime = exports.UTCTime = exports.CharacterString = exports.GeneralString = exports.VisibleString = exports.GraphicString = exports.IA5String = exports.VideotexString = exports.TeletexString = exports.PrintableString = exports.NumericString = exports.UniversalString = exports.BmpString = exports.Utf8String = exports.ObjectIdentifier = exports.Enumerated = exports.Integer = exports.BitString = exports.OctetString = exports.Null = exports.Set = exports.Sequence = exports.Boolean = exports.EndOfContent = exports.Constructed = exports.Primitive = exports.BaseBlock = undefined;
exports.fromBER = fromBER;
exports.compareSchema = compareSchema;
exports.verifySchema = verifySchema;
exports.fromJSON = fromJSON; //**************************************************************************************
//region Declaration of global variables
//**************************************************************************************
const powers2 = [new Uint8Array([1])];
/* eslint-disable indent */
/*
* Copyright (c) 2016-2018, Peculiar Ventures
* All rights reserved.
*
* Author 2016-2018, Yury Strozhevsky <www.strozhevsky.com>.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
//**************************************************************************************
const digitsString = "0123456789"; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration for "LocalBaseBlock" class
//**************************************************************************************
/**
* Class used as a base block for all remaining ASN.1 classes
* @typedef LocalBaseBlock
* @interface
* @property {number} blockLength
* @property {string} error
* @property {Array.<string>} warnings
* @property {ArrayBuffer} valueBeforeDecode
*/
class LocalBaseBlock {
//**********************************************************************************
/**
* Constructor for "LocalBaseBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueBeforeDecode]
*/
constructor(parameters = {}) {
/**
* @type {number} blockLength
*/
this.blockLength = (0, utils.getParametersValue)(parameters, "blockLength", 0);
/**
* @type {string} error
*/
this.error = (0, utils.getParametersValue)(parameters, "error", "");
/**
* @type {Array.<string>} warnings
*/
this.warnings = (0, utils.getParametersValue)(parameters, "warnings", []); //noinspection JSCheckFunctionSignatures
/**
* @type {ArrayBuffer} valueBeforeDecode
*/
if ("valueBeforeDecode" in parameters) this.valueBeforeDecode = parameters.valueBeforeDecode.slice(0);else this.valueBeforeDecode = new ArrayBuffer(0);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "baseBlock";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
return {
blockName: this.constructor.blockName(),
blockLength: this.blockLength,
error: this.error,
warnings: this.warnings,
valueBeforeDecode: (0, utils.bufferToHexCodes)(this.valueBeforeDecode, 0, this.valueBeforeDecode.byteLength)
};
} //**********************************************************************************
} //**************************************************************************************
//endregion
//**************************************************************************************
//region Description for "LocalHexBlock" class
//**************************************************************************************
/**
* Class used as a base block for all remaining ASN.1 classes
* @extends LocalBaseBlock
* @typedef LocalHexBlock
* @property {number} blockLength
* @property {string} error
* @property {Array.<string>} warnings
* @property {ArrayBuffer} valueBeforeDecode
* @property {boolean} isHexOnly
* @property {ArrayBuffer} valueHex
*/
//noinspection JSUnusedLocalSymbols
const LocalHexBlock = BaseClass => class LocalHexBlockMixin extends BaseClass {
//**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Constructor for "LocalHexBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters);
/**
* @type {boolean}
*/
this.isHexOnly = (0, utils.getParametersValue)(parameters, "isHexOnly", false);
/**
* @type {ArrayBuffer}
*/
if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "hexBlock";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
//region Initial checks
if (intBuffer.length === 0) {
this.warnings.push("Zero buffer length");
return inputOffset;
} //endregion
//region Copy input buffer to internal buffer
this.valueHex = inputBuffer.slice(inputOffset, inputOffset + inputLength); //endregion
this.blockLength = inputLength;
return inputOffset + inputLength;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
if (this.isHexOnly !== true) {
this.error = "Flag \"isHexOnly\" is not set, abort";
return new ArrayBuffer(0);
}
if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength); //noinspection JSCheckFunctionSignatures
return this.valueHex.slice(0);
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.blockName = this.constructor.blockName();
object.isHexOnly = this.isHexOnly;
object.valueHex = (0, utils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
return object;
} //**********************************************************************************
}; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of identification block class
//**************************************************************************************
class LocalIdentificationBlock extends LocalHexBlock(LocalBaseBlock) {
//**********************************************************************************
/**
* Constructor for "LocalBaseBlock" class
* @param {Object} [parameters={}]
* @property {Object} [idBlock]
*/
constructor(parameters = {}) {
super();
if ("idBlock" in parameters) {
//region Properties from hexBlock class
this.isHexOnly = (0, utils.getParametersValue)(parameters.idBlock, "isHexOnly", false);
this.valueHex = (0, utils.getParametersValue)(parameters.idBlock, "valueHex", new ArrayBuffer(0)); //endregion
this.tagClass = (0, utils.getParametersValue)(parameters.idBlock, "tagClass", -1);
this.tagNumber = (0, utils.getParametersValue)(parameters.idBlock, "tagNumber", -1);
this.isConstructed = (0, utils.getParametersValue)(parameters.idBlock, "isConstructed", false);
} else {
this.tagClass = -1;
this.tagNumber = -1;
this.isConstructed = false;
}
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "identificationBlock";
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
//region Initial variables
let firstOctet = 0;
let retBuf;
let retView; //endregion
switch (this.tagClass) {
case 1:
firstOctet |= 0x00; // UNIVERSAL
break;
case 2:
firstOctet |= 0x40; // APPLICATION
break;
case 3:
firstOctet |= 0x80; // CONTEXT-SPECIFIC
break;
case 4:
firstOctet |= 0xC0; // PRIVATE
break;
default:
this.error = "Unknown tag class";
return new ArrayBuffer(0);
}
if (this.isConstructed) firstOctet |= 0x20;
if (this.tagNumber < 31 && !this.isHexOnly) {
retBuf = new ArrayBuffer(1);
retView = new Uint8Array(retBuf);
if (!sizeOnly) {
let number = this.tagNumber;
number &= 0x1F;
firstOctet |= number;
retView[0] = firstOctet;
}
return retBuf;
}
if (this.isHexOnly === false) {
const encodedBuf = (0, utils.utilToBase)(this.tagNumber, 7);
const encodedView = new Uint8Array(encodedBuf);
const size = encodedBuf.byteLength;
retBuf = new ArrayBuffer(size + 1);
retView = new Uint8Array(retBuf);
retView[0] = firstOctet | 0x1F;
if (!sizeOnly) {
for (let i = 0; i < size - 1; i++) retView[i + 1] = encodedView[i] | 0x80;
retView[size] = encodedView[size - 1];
}
return retBuf;
}
retBuf = new ArrayBuffer(this.valueHex.byteLength + 1);
retView = new Uint8Array(retBuf);
retView[0] = firstOctet | 0x1F;
if (sizeOnly === false) {
const curView = new Uint8Array(this.valueHex);
for (let i = 0; i < curView.length - 1; i++) retView[i + 1] = curView[i] | 0x80;
retView[this.valueHex.byteLength] = curView[curView.length - 1];
}
return retBuf;
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
//region Initial checks
if (intBuffer.length === 0) {
this.error = "Zero buffer length";
return -1;
} //endregion
//region Find tag class
const tagClassMask = intBuffer[0] & 0xC0;
switch (tagClassMask) {
case 0x00:
this.tagClass = 1; // UNIVERSAL
break;
case 0x40:
this.tagClass = 2; // APPLICATION
break;
case 0x80:
this.tagClass = 3; // CONTEXT-SPECIFIC
break;
case 0xC0:
this.tagClass = 4; // PRIVATE
break;
default:
this.error = "Unknown tag class";
return -1;
} //endregion
//region Find it's constructed or not
this.isConstructed = (intBuffer[0] & 0x20) === 0x20; //endregion
//region Find tag number
this.isHexOnly = false;
const tagNumberMask = intBuffer[0] & 0x1F; //region Simple case (tag number < 31)
if (tagNumberMask !== 0x1F) {
this.tagNumber = tagNumberMask;
this.blockLength = 1;
} //endregion
//region Tag number bigger or equal to 31
else {
let count = 1;
this.valueHex = new ArrayBuffer(255);
let tagNumberBufferMaxLength = 255;
let intTagNumberBuffer = new Uint8Array(this.valueHex); //noinspection JSBitwiseOperatorUsage
while (intBuffer[count] & 0x80) {
intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F;
count++;
if (count >= intBuffer.length) {
this.error = "End of input reached before message was fully decoded";
return -1;
} //region In case if tag number length is greater than 255 bytes (rare but possible case)
if (count === tagNumberBufferMaxLength) {
tagNumberBufferMaxLength += 255;
const tempBuffer = new ArrayBuffer(tagNumberBufferMaxLength);
const tempBufferView = new Uint8Array(tempBuffer);
for (let i = 0; i < intTagNumberBuffer.length; i++) tempBufferView[i] = intTagNumberBuffer[i];
this.valueHex = new ArrayBuffer(tagNumberBufferMaxLength);
intTagNumberBuffer = new Uint8Array(this.valueHex);
} //endregion
}
this.blockLength = count + 1;
intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer
//region Cut buffer
const tempBuffer = new ArrayBuffer(count);
const tempBufferView = new Uint8Array(tempBuffer);
for (let i = 0; i < count; i++) tempBufferView[i] = intTagNumberBuffer[i];
this.valueHex = new ArrayBuffer(count);
intTagNumberBuffer = new Uint8Array(this.valueHex);
intTagNumberBuffer.set(tempBufferView); //endregion
//region Try to convert long tag number to short form
if (this.blockLength <= 9) this.tagNumber = (0, utils.utilFromBase)(intTagNumberBuffer, 7);else {
this.isHexOnly = true;
this.warnings.push("Tag too long, represented as hex-coded");
} //endregion
} //endregion
//endregion
//region Check if constructed encoding was using for primitive type
if (this.tagClass === 1 && this.isConstructed) {
switch (this.tagNumber) {
case 1: // Boolean
case 2: // REAL
case 5: // Null
case 6: // OBJECT IDENTIFIER
case 9: // REAL
case 14: // Time
case 23:
case 24:
case 31:
case 32:
case 33:
case 34:
this.error = "Constructed encoding used for primitive type";
return -1;
default:
}
} //endregion
return inputOffset + this.blockLength; // Return current offset in input buffer
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName: string,
* tagClass: number,
* tagNumber: number,
* isConstructed: boolean,
* isHexOnly: boolean,
* valueHex: ArrayBuffer,
* blockLength: number,
* error: string, warnings: Array.<string>,
* valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.blockName = this.constructor.blockName();
object.tagClass = this.tagClass;
object.tagNumber = this.tagNumber;
object.isConstructed = this.isConstructed;
return object;
} //**********************************************************************************
} //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of length block class
//**************************************************************************************
class LocalLengthBlock extends LocalBaseBlock {
//**********************************************************************************
/**
* Constructor for "LocalLengthBlock" class
* @param {Object} [parameters={}]
* @property {Object} [lenBlock]
*/
constructor(parameters = {}) {
super();
if ("lenBlock" in parameters) {
this.isIndefiniteForm = (0, utils.getParametersValue)(parameters.lenBlock, "isIndefiniteForm", false);
this.longFormUsed = (0, utils.getParametersValue)(parameters.lenBlock, "longFormUsed", false);
this.length = (0, utils.getParametersValue)(parameters.lenBlock, "length", 0);
} else {
this.isIndefiniteForm = false;
this.longFormUsed = false;
this.length = 0;
}
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "lengthBlock";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
//region Initial checks
if (intBuffer.length === 0) {
this.error = "Zero buffer length";
return -1;
}
if (intBuffer[0] === 0xFF) {
this.error = "Length block 0xFF is reserved by standard";
return -1;
} //endregion
//region Check for length form type
this.isIndefiniteForm = intBuffer[0] === 0x80; //endregion
//region Stop working in case of indefinite length form
if (this.isIndefiniteForm === true) {
this.blockLength = 1;
return inputOffset + this.blockLength;
} //endregion
//region Check is long form of length encoding using
this.longFormUsed = !!(intBuffer[0] & 0x80); //endregion
//region Stop working in case of short form of length value
if (this.longFormUsed === false) {
this.length = intBuffer[0];
this.blockLength = 1;
return inputOffset + this.blockLength;
} //endregion
//region Calculate length value in case of long form
const count = intBuffer[0] & 0x7F;
if (count > 8) // Too big length value
{
this.error = "Too big integer";
return -1;
}
if (count + 1 > intBuffer.length) {
this.error = "End of input reached before message was fully decoded";
return -1;
}
const lengthBufferView = new Uint8Array(count);
for (let i = 0; i < count; i++) lengthBufferView[i] = intBuffer[i + 1];
if (lengthBufferView[count - 1] === 0x00) this.warnings.push("Needlessly long encoded length");
this.length = (0, utils.utilFromBase)(lengthBufferView, 8);
if (this.longFormUsed && this.length <= 127) this.warnings.push("Unneccesary usage of long length form");
this.blockLength = count + 1; //endregion
return inputOffset + this.blockLength; // Return current offset in input buffer
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
//region Initial variables
let retBuf;
let retView; //endregion
if (this.length > 127) this.longFormUsed = true;
if (this.isIndefiniteForm) {
retBuf = new ArrayBuffer(1);
if (sizeOnly === false) {
retView = new Uint8Array(retBuf);
retView[0] = 0x80;
}
return retBuf;
}
if (this.longFormUsed === true) {
const encodedBuf = (0, utils.utilToBase)(this.length, 8);
if (encodedBuf.byteLength > 127) {
this.error = "Too big length";
return new ArrayBuffer(0);
}
retBuf = new ArrayBuffer(encodedBuf.byteLength + 1);
if (sizeOnly === true) return retBuf;
const encodedView = new Uint8Array(encodedBuf);
retView = new Uint8Array(retBuf);
retView[0] = encodedBuf.byteLength | 0x80;
for (let i = 0; i < encodedBuf.byteLength; i++) retView[i + 1] = encodedView[i];
return retBuf;
}
retBuf = new ArrayBuffer(1);
if (sizeOnly === false) {
retView = new Uint8Array(retBuf);
retView[0] = this.length;
}
return retBuf;
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.blockName = this.constructor.blockName();
object.isIndefiniteForm = this.isIndefiniteForm;
object.longFormUsed = this.longFormUsed;
object.length = this.length;
return object;
} //**********************************************************************************
} //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of value block class
//**************************************************************************************
class LocalValueBlock extends LocalBaseBlock {
//**********************************************************************************
/**
* Constructor for "LocalValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "valueBlock";
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols,JSUnusedLocalSymbols
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Throw an exception for a function which needs to be specified in extended classes
throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); //endregion
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
//region Throw an exception for a function which needs to be specified in extended classes
throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); //endregion
} //**********************************************************************************
} //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of basic ASN.1 block class
//**************************************************************************************
class BaseBlock extends LocalBaseBlock {
//**********************************************************************************
/**
* Constructor for "BaseBlock" class
* @param {Object} [parameters={}]
* @property {Object} [primitiveSchema]
* @property {string} [name]
* @property {boolean} [optional]
* @param valueBlockType Type of value block
*/
constructor(parameters = {}, valueBlockType = LocalValueBlock) {
super(parameters);
if ("name" in parameters) this.name = parameters.name;
if ("optional" in parameters) this.optional = parameters.optional;
if ("primitiveSchema" in parameters) this.primitiveSchema = parameters.primitiveSchema;
this.idBlock = new LocalIdentificationBlock(parameters);
this.lenBlock = new LocalLengthBlock(parameters);
this.valueBlock = new valueBlockType(parameters);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "BaseBlock";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
let retBuf;
const idBlockBuf = this.idBlock.toBER(sizeOnly);
const valueBlockSizeBuf = this.valueBlock.toBER(true);
this.lenBlock.length = valueBlockSizeBuf.byteLength;
const lenBlockBuf = this.lenBlock.toBER(sizeOnly);
retBuf = (0, utils.utilConcatBuf)(idBlockBuf, lenBlockBuf);
let valueBlockBuf;
if (sizeOnly === false) valueBlockBuf = this.valueBlock.toBER(sizeOnly);else valueBlockBuf = new ArrayBuffer(this.lenBlock.length);
retBuf = (0, utils.utilConcatBuf)(retBuf, valueBlockBuf);
if (this.lenBlock.isIndefiniteForm === true) {
const indefBuf = new ArrayBuffer(2);
if (sizeOnly === false) {
const indefView = new Uint8Array(indefBuf);
indefView[0] = 0x00;
indefView[1] = 0x00;
}
retBuf = (0, utils.utilConcatBuf)(retBuf, indefBuf);
}
return retBuf;
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.idBlock = this.idBlock.toJSON();
object.lenBlock = this.lenBlock.toJSON();
object.valueBlock = this.valueBlock.toJSON();
if ("name" in this) object.name = this.name;
if ("optional" in this) object.optional = this.optional;
if ("primitiveSchema" in this) object.primitiveSchema = this.primitiveSchema.toJSON();
return object;
} //**********************************************************************************
}
exports.BaseBlock = BaseBlock; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of basic block for all PRIMITIVE types
//**************************************************************************************
class LocalPrimitiveValueBlock extends LocalValueBlock {
//**********************************************************************************
/**
* Constructor for "LocalPrimitiveValueBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueBeforeDecode]
*/
constructor(parameters = {}) {
super(parameters); //region Variables from "hexBlock" class
if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0);
this.isHexOnly = (0, utils.getParametersValue)(parameters, "isHexOnly", true); //endregion
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
//region Initial checks
if (intBuffer.length === 0) {
this.warnings.push("Zero buffer length");
return inputOffset;
} //endregion
//region Copy input buffer into internal buffer
this.valueHex = new ArrayBuffer(intBuffer.length);
const valueHexView = new Uint8Array(this.valueHex);
for (let i = 0; i < intBuffer.length; i++) valueHexView[i] = intBuffer[i]; //endregion
this.blockLength = inputLength;
return inputOffset + inputLength;
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
return this.valueHex.slice(0);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "PrimitiveValueBlock";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.valueHex = (0, utils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
object.isHexOnly = this.isHexOnly;
return object;
} //**********************************************************************************
} //**************************************************************************************
class Primitive extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "Primitive" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters, LocalPrimitiveValueBlock);
this.idBlock.isConstructed = false;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "PRIMITIVE";
} //**********************************************************************************
}
exports.Primitive = Primitive; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of basic block for all CONSTRUCTED types
//**************************************************************************************
class LocalConstructedValueBlock extends LocalValueBlock {
//**********************************************************************************
/**
* Constructor for "LocalConstructedValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.value = (0, utils.getParametersValue)(parameters, "value", []);
this.isIndefiniteForm = (0, utils.getParametersValue)(parameters, "isIndefiniteForm", false);
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Store initial offset and length
const initialOffset = inputOffset;
const initialLength = inputLength; //endregion
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
//region Initial checks
if (intBuffer.length === 0) {
this.warnings.push("Zero buffer length");
return inputOffset;
} //endregion
//region Aux function
function checkLen(indefiniteLength, length) {
if (indefiniteLength === true) return 1;
return length;
} //endregion
let currentOffset = inputOffset;
while (checkLen(this.isIndefiniteForm, inputLength) > 0) {
const returnObject = LocalFromBER(inputBuffer, currentOffset, inputLength);
if (returnObject.offset === -1) {
this.error = returnObject.result.error;
this.warnings.concat(returnObject.result.warnings);
return -1;
}
currentOffset = returnObject.offset;
this.blockLength += returnObject.result.blockLength;
inputLength -= returnObject.result.blockLength;
this.value.push(returnObject.result);
if (this.isIndefiniteForm === true && returnObject.result.constructor.blockName() === EndOfContent.blockName()) break;
}
if (this.isIndefiniteForm === true) {
if (this.value[this.value.length - 1].constructor.blockName() === EndOfContent.blockName()) this.value.pop();else this.warnings.push("No EndOfContent block encoded");
} //region Copy "inputBuffer" to "valueBeforeDecode"
this.valueBeforeDecode = inputBuffer.slice(initialOffset, initialOffset + initialLength); //endregion
return currentOffset;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
let retBuf = new ArrayBuffer(0);
for (let i = 0; i < this.value.length; i++) {
const valueBuf = this.value[i].toBER(sizeOnly);
retBuf = (0, utils.utilConcatBuf)(retBuf, valueBuf);
}
return retBuf;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "ConstructedValueBlock";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.isIndefiniteForm = this.isIndefiniteForm;
object.value = [];
for (let i = 0; i < this.value.length; i++) object.value.push(this.value[i].toJSON());
return object;
} //**********************************************************************************
} //**************************************************************************************
class Constructed extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "Constructed" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalConstructedValueBlock);
this.idBlock.isConstructed = true;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "CONSTRUCTED";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
}
exports.Constructed = Constructed; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 EndOfContent type class
//**************************************************************************************
class LocalEndOfContentValueBlock extends LocalValueBlock {
//**********************************************************************************
/**
* Constructor for "LocalEndOfContentValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number}
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region There is no "value block" for EndOfContent type and we need to return the same offset
return inputOffset; //endregion
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
return new ArrayBuffer(0);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "EndOfContentValueBlock";
} //**********************************************************************************
} //**************************************************************************************
class EndOfContent extends BaseBlock {
//**********************************************************************************
constructor(paramaters = {}) {
super(paramaters, LocalEndOfContentValueBlock);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 0; // EndOfContent
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "EndOfContent";
} //**********************************************************************************
}
exports.EndOfContent = EndOfContent; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 Boolean type class
//**************************************************************************************
class LocalBooleanValueBlock extends LocalValueBlock {
//**********************************************************************************
/**
* Constructor for "LocalBooleanValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.value = (0, utils.getParametersValue)(parameters, "value", false);
this.isHexOnly = (0, utils.getParametersValue)(parameters, "isHexOnly", false);
if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else {
this.valueHex = new ArrayBuffer(1);
if (this.value === true) {
const view = new Uint8Array(this.valueHex);
view[0] = 0xFF;
}
}
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
if (inputLength > 1) this.warnings.push("Boolean value encoded in more then 1 octet");
this.isHexOnly = true; //region Copy input buffer to internal array
this.valueHex = new ArrayBuffer(intBuffer.length);
const view = new Uint8Array(this.valueHex);
for (let i = 0; i < intBuffer.length; i++) view[i] = intBuffer[i]; //endregion
if (utils.utilDecodeTC.call(this) !== 0) this.value = true;else this.value = false;
this.blockLength = inputLength;
return inputOffset + inputLength;
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
return this.valueHex;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "BooleanValueBlock";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.value = this.value;
object.isHexOnly = this.isHexOnly;
object.valueHex = (0, utils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
return object;
} //**********************************************************************************
} //**************************************************************************************
class Boolean extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "Boolean" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalBooleanValueBlock);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 1; // Boolean
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Boolean";
} //**********************************************************************************
}
exports.Boolean = Boolean; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 Sequence and Set type classes
//**************************************************************************************
class Sequence extends Constructed {
//**********************************************************************************
/**
* Constructor for "Sequence" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 16; // Sequence
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Sequence";
} //**********************************************************************************
}
exports.Sequence = Sequence; //**************************************************************************************
class Set extends Constructed {
//**********************************************************************************
/**
* Constructor for "Set" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 17; // Set
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Set";
} //**********************************************************************************
}
exports.Set = Set; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 Null type class
//**************************************************************************************
class Null extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "Null" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalBaseBlock); // We will not have a call to "Null value block" because of specified "fromBER" and "toBER" functions
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 5; // Null
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Null";
} //**********************************************************************************
//noinspection JSUnusedLocalSymbols
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
if (this.lenBlock.length > 0) this.warnings.push("Non-zero length of value block for Null type");
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
this.blockLength += inputLength;
if (inputOffset + inputLength > inputBuffer.byteLength) {
this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
return -1;
}
return inputOffset + inputLength;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
const retBuf = new ArrayBuffer(2);
if (sizeOnly === true) return retBuf;
const retView = new Uint8Array(retBuf);
retView[0] = 0x05;
retView[1] = 0x00;
return retBuf;
} //**********************************************************************************
}
exports.Null = Null; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 OctetString type class
//**************************************************************************************
class LocalOctetStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) {
//**********************************************************************************
/**
* Constructor for "LocalOctetStringValueBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters);
this.isConstructed = (0, utils.getParametersValue)(parameters, "isConstructed", false);
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
let resultOffset = 0;
if (this.isConstructed === true) {
this.isHexOnly = false;
resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
if (resultOffset === -1) return resultOffset;
for (let i = 0; i < this.value.length; i++) {
const currentBlockName = this.value[i].constructor.blockName();
if (currentBlockName === EndOfContent.blockName()) {
if (this.isIndefiniteForm === true) break;else {
this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only";
return -1;
}
}
if (currentBlockName !== OctetString.blockName()) {
this.error = "OCTET STRING may consists of OCTET STRINGs only";
return -1;
}
}
} else {
this.isHexOnly = true;
resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
this.blockLength = inputLength;
}
return resultOffset;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly);
let retBuf = new ArrayBuffer(this.valueHex.byteLength);
if (sizeOnly === true) return retBuf;
if (this.valueHex.byteLength === 0) return retBuf;
retBuf = this.valueHex.slice(0);
return retBuf;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "OctetStringValueBlock";
} //**********************************************************************************
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.isConstructed = this.isConstructed;
object.isHexOnly = this.isHexOnly;
object.valueHex = (0, utils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
return object;
} //**********************************************************************************
} //**************************************************************************************
class OctetString extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "OctetString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalOctetStringValueBlock);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 4; // OctetString
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
this.valueBlock.isConstructed = this.idBlock.isConstructed;
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; //region Ability to encode empty OCTET STRING
if (inputLength === 0) {
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
return inputOffset;
} //endregion
return super.fromBER(inputBuffer, inputOffset, inputLength);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "OctetString";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Checking that two OCTETSTRINGs are equal
* @param {OctetString} octetString
*/
isEqual(octetString) {
//region Check input type
if (octetString instanceof OctetString === false) return false; //endregion
//region Compare two JSON strings
if (JSON.stringify(this) !== JSON.stringify(octetString)) return false; //endregion
return true;
} //**********************************************************************************
}
exports.OctetString = OctetString; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 BitString type class
//**************************************************************************************
class LocalBitStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) {
//**********************************************************************************
/**
* Constructor for "LocalBitStringValueBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters);
this.unusedBits = (0, utils.getParametersValue)(parameters, "unusedBits", 0);
this.isConstructed = (0, utils.getParametersValue)(parameters, "isConstructed", false);
this.blockLength = this.valueHex.byteLength;
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Ability to decode zero-length BitString value
if (inputLength === 0) return inputOffset; //endregion
let resultOffset = -1; //region If the BISTRING supposed to be a constructed value
if (this.isConstructed === true) {
resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
if (resultOffset === -1) return resultOffset;
for (let i = 0; i < this.value.length; i++) {
const currentBlockName = this.value[i].constructor.blockName();
if (currentBlockName === EndOfContent.blockName()) {
if (this.isIndefiniteForm === true) break;else {
this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only";
return -1;
}
}
if (currentBlockName !== BitString.blockName()) {
this.error = "BIT STRING may consists of BIT STRINGs only";
return -1;
}
if (this.unusedBits > 0 && this.value[i].valueBlock.unusedBits > 0) {
this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only";
return -1;
}
this.unusedBits = this.value[i].valueBlock.unusedBits;
if (this.unusedBits > 7) {
this.error = "Unused bits for BitString must be in range 0-7";
return -1;
}
}
return resultOffset;
} //endregion
//region If the BitString supposed to be a primitive value
//region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
this.unusedBits = intBuffer[0];
if (this.unusedBits > 7) {
this.error = "Unused bits for BitString must be in range 0-7";
return -1;
} //region Copy input buffer to internal buffer
this.valueHex = new ArrayBuffer(intBuffer.length - 1);
const view = new Uint8Array(this.valueHex);
for (let i = 0; i < inputLength - 1; i++) view[i] = intBuffer[i + 1]; //endregion
this.blockLength = intBuffer.length;
return inputOffset + inputLength; //endregion
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly);
if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength + 1);
if (this.valueHex.byteLength === 0) return new ArrayBuffer(0);
const curView = new Uint8Array(this.valueHex);
const retBuf = new ArrayBuffer(this.valueHex.byteLength + 1);
const retView = new Uint8Array(retBuf);
retView[0] = this.unusedBits;
for (let i = 0; i < this.valueHex.byteLength; i++) retView[i + 1] = curView[i];
return retBuf;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "BitStringValueBlock";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.unusedBits = this.unusedBits;
object.isConstructed = this.isConstructed;
object.isHexOnly = this.isHexOnly;
object.valueHex = (0, utils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
return object;
} //**********************************************************************************
} //**************************************************************************************
class BitString extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "BitString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalBitStringValueBlock);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 3; // BitString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "BitString";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
//region Ability to encode empty BitString
if (inputLength === 0) return inputOffset; //endregion
this.valueBlock.isConstructed = this.idBlock.isConstructed;
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
return super.fromBER(inputBuffer, inputOffset, inputLength);
} //**********************************************************************************
/**
* Checking that two BITSTRINGs are equal
* @param {BitString} bitString
*/
isEqual(bitString) {
//region Check input type
if (bitString instanceof BitString === false) return false; //endregion
//region Compare two JSON strings
if (JSON.stringify(this) !== JSON.stringify(bitString)) return false; //endregion
return true;
} //**********************************************************************************
}
exports.BitString = BitString; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 Integer type class
//**************************************************************************************
/**
* @extends LocalValueBlock
*/
class LocalIntegerValueBlock extends LocalHexBlock(LocalValueBlock) {
//**********************************************************************************
/**
* Constructor for "LocalIntegerValueBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters);
if ("value" in parameters) this.valueDec = parameters.value;
} //**********************************************************************************
/**
* Setter for "valueHex"
* @param {ArrayBuffer} _value
*/
set valueHex(_value) {
this._valueHex = _value.slice(0);
if (_value.byteLength >= 4) {
this.warnings.push("Too big Integer for decoding, hex only");
this.isHexOnly = true;
this._valueDec = 0;
} else {
this.isHexOnly = false;
if (_value.byteLength > 0) this._valueDec = utils.utilDecodeTC.call(this);
}
} //**********************************************************************************
/**
* Getter for "valueHex"
* @returns {ArrayBuffer}
*/
get valueHex() {
return this._valueHex;
} //**********************************************************************************
/**
* Getter for "valueDec"
* @param {number} _value
*/
set valueDec(_value) {
this._valueDec = _value;
this.isHexOnly = false;
this._valueHex = (0, utils.utilEncodeTC)(_value);
} //**********************************************************************************
/**
* Getter for "valueDec"
* @returns {number}
*/
get valueDec() {
return this._valueDec;
} //**********************************************************************************
/**
* Base function for converting block from DER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 DER encoded array
* @param {!number} inputOffset Offset in ASN.1 DER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @param {number} [expectedLength=0] Expected length of converted "valueHex" buffer
* @returns {number} Offset after least decoded byte
*/
fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) {
const offset = this.fromBER(inputBuffer, inputOffset, inputLength);
if (offset === -1) return offset;
const view = new Uint8Array(this._valueHex);
if (view[0] === 0x00 && (view[1] & 0x80) !== 0) {
const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1);
const updatedView = new Uint8Array(updatedValueHex);
updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1));
this._valueHex = updatedValueHex.slice(0);
} else {
if (expectedLength !== 0) {
if (this._valueHex.byteLength < expectedLength) {
if (expectedLength - this._valueHex.byteLength > 1) expectedLength = this._valueHex.byteLength + 1;
const updatedValueHex = new ArrayBuffer(expectedLength);
const updatedView = new Uint8Array(updatedValueHex);
updatedView.set(view, expectedLength - this._valueHex.byteLength);
this._valueHex = updatedValueHex.slice(0);
}
}
}
return offset;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (DER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toDER(sizeOnly = false) {
const view = new Uint8Array(this._valueHex);
switch (true) {
case (view[0] & 0x80) !== 0:
{
const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength + 1);
const updatedView = new Uint8Array(updatedValueHex);
updatedView[0] = 0x00;
updatedView.set(view, 1);
this._valueHex = updatedValueHex.slice(0);
}
break;
case view[0] === 0x00 && (view[1] & 0x80) === 0:
{
const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1);
const updatedView = new Uint8Array(updatedValueHex);
updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1));
this._valueHex = updatedValueHex.slice(0);
}
break;
default:
}
return this.toBER(sizeOnly);
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
if (resultOffset === -1) return resultOffset;
this.blockLength = inputLength;
return inputOffset + inputLength;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
//noinspection JSCheckFunctionSignatures
return this.valueHex.slice(0);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "IntegerValueBlock";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.valueDec = this.valueDec;
return object;
} //**********************************************************************************
/**
* Convert current value to decimal string representation
*/
toString() {
//region Aux functions
function viewAdd(first, second) {
//region Initial variables
const c = new Uint8Array([0]);
let firstView = new Uint8Array(first);
let secondView = new Uint8Array(second);
let firstViewCopy = firstView.slice(0);
const firstViewCopyLength = firstViewCopy.length - 1;
let secondViewCopy = secondView.slice(0);
const secondViewCopyLength = secondViewCopy.length - 1;
let value = 0;
const max = secondViewCopyLength < firstViewCopyLength ? firstViewCopyLength : secondViewCopyLength;
let counter = 0; //endregion
for (let i = max; i >= 0; i--, counter++) {
switch (true) {
case counter < secondViewCopy.length:
value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0];
break;
default:
value = firstViewCopy[firstViewCopyLength - counter] + c[0];
}
c[0] = value / 10;
switch (true) {
case counter >= firstViewCopy.length:
firstViewCopy = (0, utils.utilConcatView)(new Uint8Array([value % 10]), firstViewCopy);
break;
default:
firstViewCopy[firstViewCopyLength - counter] = value % 10;
}
}
if (c[0] > 0) firstViewCopy = (0, utils.utilConcatView)(c, firstViewCopy);
return firstViewCopy.slice(0);
}
function power2(n) {
if (n >= powers2.length) {
for (let p = powers2.length; p <= n; p++) {
const c = new Uint8Array([0]);
let digits = powers2[p - 1].slice(0);
for (let i = digits.length - 1; i >= 0; i--) {
const newValue = new Uint8Array([(digits[i] << 1) + c[0]]);
c[0] = newValue[0] / 10;
digits[i] = newValue[0] % 10;
}
if (c[0] > 0) digits = (0, utils.utilConcatView)(c, digits);
powers2.push(digits);
}
}
return powers2[n];
}
function viewSub(first, second) {
//region Initial variables
let b = 0;
let firstView = new Uint8Array(first);
let secondView = new Uint8Array(second);
let firstViewCopy = firstView.slice(0);
const firstViewCopyLength = firstViewCopy.length - 1;
let secondViewCopy = secondView.slice(0);
const secondViewCopyLength = secondViewCopy.length - 1;
let value;
let counter = 0; //endregion
for (let i = secondViewCopyLength; i >= 0; i--, counter++) {
value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b;
switch (true) {
case value < 0:
b = 1;
firstViewCopy[firstViewCopyLength - counter] = value + 10;
break;
default:
b = 0;
firstViewCopy[firstViewCopyLength - counter] = value;
}
}
if (b > 0) {
for (let i = firstViewCopyLength - secondViewCopyLength + 1; i >= 0; i--, counter++) {
value = firstViewCopy[firstViewCopyLength - counter] - b;
if (value < 0) {
b = 1;
firstViewCopy[firstViewCopyLength - counter] = value + 10;
} else {
b = 0;
firstViewCopy[firstViewCopyLength - counter] = value;
break;
}
}
}
return firstViewCopy.slice();
} //endregion
//region Initial variables
const firstBit = this._valueHex.byteLength * 8 - 1;
let digits = new Uint8Array(this._valueHex.byteLength * 8 / 3);
let bitNumber = 0;
let currentByte;
const asn1View = new Uint8Array(this._valueHex);
let result = "";
let flag = false; //endregion
//region Calculate number
for (let byteNumber = this._valueHex.byteLength - 1; byteNumber >= 0; byteNumber--) {
currentByte = asn1View[byteNumber];
for (let i = 0; i < 8; i++) {
if ((currentByte & 1) === 1) {
switch (bitNumber) {
case firstBit:
digits = viewSub(power2(bitNumber), digits);
result = "-";
break;
default:
digits = viewAdd(digits, power2(bitNumber));
}
}
bitNumber++;
currentByte >>= 1;
}
} //endregion
//region Print number
for (let i = 0; i < digits.length; i++) {
if (digits[i]) flag = true;
if (flag) result += digitsString.charAt(digits[i]);
}
if (flag === false) result += digitsString.charAt(0); //endregion
return result;
} //**********************************************************************************
} //**************************************************************************************
class Integer extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "Integer" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalIntegerValueBlock);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 2; // Integer
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Integer";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Compare two Integer object, or Integer and ArrayBuffer objects
* @param {!Integer|ArrayBuffer} otherValue
* @returns {boolean}
*/
isEqual(otherValue) {
if (otherValue instanceof Integer) {
if (this.valueBlock.isHexOnly && otherValue.valueBlock.isHexOnly) // Compare two ArrayBuffers
return (0, utils.isEqualBuffer)(this.valueBlock.valueHex, otherValue.valueBlock.valueHex);
if (this.valueBlock.isHexOnly === otherValue.valueBlock.isHexOnly) return this.valueBlock.valueDec === otherValue.valueBlock.valueDec;
return false;
}
if (otherValue instanceof ArrayBuffer) return (0, utils.isEqualBuffer)(this.valueBlock.valueHex, otherValue);
return false;
} //**********************************************************************************
/**
* Convert current Integer value from BER into DER format
* @returns {Integer}
*/
convertToDER() {
const integer = new Integer({
valueHex: this.valueBlock.valueHex
});
integer.valueBlock.toDER();
return integer;
} //**********************************************************************************
/**
* Convert current Integer value from DER to BER format
* @returns {Integer}
*/
convertFromDER() {
const expectedLength = this.valueBlock.valueHex.byteLength % 2 ? this.valueBlock.valueHex.byteLength + 1 : this.valueBlock.valueHex.byteLength;
const integer = new Integer({
valueHex: this.valueBlock.valueHex
});
integer.valueBlock.fromDER(integer.valueBlock.valueHex, 0, integer.valueBlock.valueHex.byteLength, expectedLength);
return integer;
} //**********************************************************************************
}
exports.Integer = Integer; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 Enumerated type class
//**************************************************************************************
class Enumerated extends Integer {
//**********************************************************************************
/**
* Constructor for "Enumerated" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 10; // Enumerated
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Enumerated";
} //**********************************************************************************
}
exports.Enumerated = Enumerated; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of ASN.1 ObjectIdentifier type class
//**************************************************************************************
class LocalSidValueBlock extends LocalHexBlock(LocalBaseBlock) {
//**********************************************************************************
/**
* Constructor for "LocalSidValueBlock" class
* @param {Object} [parameters={}]
* @property {number} [valueDec]
* @property {boolean} [isFirstSid]
*/
constructor(parameters = {}) {
super(parameters);
this.valueDec = (0, utils.getParametersValue)(parameters, "valueDec", -1);
this.isFirstSid = (0, utils.getParametersValue)(parameters, "isFirstSid", false);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "sidBlock";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
if (inputLength === 0) return inputOffset; //region Basic check for parameters
//noinspection JSCheckFunctionSignatures
if ((0, utils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; //endregion
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
this.valueHex = new ArrayBuffer(inputLength);
let view = new Uint8Array(this.valueHex);
for (let i = 0; i < inputLength; i++) {
view[i] = intBuffer[i] & 0x7F;
this.blockLength++;
if ((intBuffer[i] & 0x80) === 0x00) break;
} //region Ajust size of valueHex buffer
const tempValueHex = new ArrayBuffer(this.blockLength);
const tempView = new Uint8Array(tempValueHex);
for (let i = 0; i < this.blockLength; i++) tempView[i] = view[i]; //noinspection JSCheckFunctionSignatures
this.valueHex = tempValueHex.slice(0);
view = new Uint8Array(this.valueHex); //endregion
if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) {
this.error = "End of input reached before message was fully decoded";
return -1;
}
if (view[0] === 0x00) this.warnings.push("Needlessly long format of SID encoding");
if (this.blockLength <= 8) this.valueDec = (0, utils.utilFromBase)(view, 7);else {
this.isHexOnly = true;
this.warnings.push("Too big SID for decoding, hex only");
}
return inputOffset + this.blockLength;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
//region Initial variables
let retBuf;
let retView; //endregion
if (this.isHexOnly) {
if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength);
const curView = new Uint8Array(this.valueHex);
retBuf = new ArrayBuffer(this.blockLength);
retView = new Uint8Array(retBuf);
for (let i = 0; i < this.blockLength - 1; i++) retView[i] = curView[i] | 0x80;
retView[this.blockLength - 1] = curView[this.blockLength - 1];
return retBuf;
}
const encodedBuf = (0, utils.utilToBase)(this.valueDec, 7);
if (encodedBuf.byteLength === 0) {
this.error = "Error during encoding SID value";
return new ArrayBuffer(0);
}
retBuf = new ArrayBuffer(encodedBuf.byteLength);
if (sizeOnly === false) {
const encodedView = new Uint8Array(encodedBuf);
retView = new Uint8Array(retBuf);
for (let i = 0; i < encodedBuf.byteLength - 1; i++) retView[i] = encodedView[i] | 0x80;
retView[encodedBuf.byteLength - 1] = encodedView[encodedBuf.byteLength - 1];
}
return retBuf;
} //**********************************************************************************
/**
* Create string representation of current SID block
* @returns {string}
*/
toString() {
let result = "";
if (this.isHexOnly === true) result = (0, utils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);else {
if (this.isFirstSid) {
let sidValue = this.valueDec;
if (this.valueDec <= 39) result = "0.";else {
if (this.valueDec <= 79) {
result = "1.";
sidValue -= 40;
} else {
result = "2.";
sidValue -= 80;
}
}
result += sidValue.toString();
} else result = this.valueDec.toString();
}
return result;
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.valueDec = this.valueDec;
object.isFirstSid = this.isFirstSid;
return object;
} //**********************************************************************************
} //**************************************************************************************
class LocalObjectIdentifierValueBlock extends LocalValueBlock {
//**********************************************************************************
/**
* Constructor for "LocalObjectIdentifierValueBlock" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters);
this.fromString((0, utils.getParametersValue)(parameters, "value", ""));
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
let resultOffset = inputOffset;
while (inputLength > 0) {
const sidBlock = new LocalSidValueBlock();
resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength);
if (resultOffset === -1) {
this.blockLength = 0;
this.error = sidBlock.error;
return resultOffset;
}
if (this.value.length === 0) sidBlock.isFirstSid = true;
this.blockLength += sidBlock.blockLength;
inputLength -= sidBlock.blockLength;
this.value.push(sidBlock);
}
return resultOffset;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
let retBuf = new ArrayBuffer(0);
for (let i = 0; i < this.value.length; i++) {
const valueBuf = this.value[i].toBER(sizeOnly);
if (valueBuf.byteLength === 0) {
this.error = this.value[i].error;
return new ArrayBuffer(0);
}
retBuf = (0, utils.utilConcatBuf)(retBuf, valueBuf);
}
return retBuf;
} //**********************************************************************************
/**
* Create "LocalObjectIdentifierValueBlock" class from string
* @param {string} string Input string to convert from
* @returns {boolean}
*/
fromString(string) {
this.value = []; // Clear existing SID values
let pos1 = 0;
let pos2 = 0;
let sid = "";
let flag = false;
do {
pos2 = string.indexOf(".", pos1);
if (pos2 === -1) sid = string.substr(pos1);else sid = string.substr(pos1, pos2 - pos1);
pos1 = pos2 + 1;
if (flag) {
const sidBlock = this.value[0];
let plus = 0;
switch (sidBlock.valueDec) {
case 0:
break;
case 1:
plus = 40;
break;
case 2:
plus = 80;
break;
default:
this.value = []; // clear SID array
return false;
// ???
}
const parsedSID = parseInt(sid, 10);
if (isNaN(parsedSID)) return true;
sidBlock.valueDec = parsedSID + plus;
flag = false;
} else {
const sidBlock = new LocalSidValueBlock();
sidBlock.valueDec = parseInt(sid, 10);
if (isNaN(sidBlock.valueDec)) return true;
if (this.value.length === 0) {
sidBlock.isFirstSid = true;
flag = true;
}
this.value.push(sidBlock);
}
} while (pos2 !== -1);
return true;
} //**********************************************************************************
/**
* Converts "LocalObjectIdentifierValueBlock" class to string
* @returns {string}
*/
toString() {
let result = "";
let isHexOnly = false;
for (let i = 0; i < this.value.length; i++) {
isHexOnly = this.value[i].isHexOnly;
let sidStr = this.value[i].toString();
if (i !== 0) result = `${result}.`;
if (isHexOnly) {
sidStr = `{${sidStr}}`;
if (this.value[i].isFirstSid) result = `2.{${sidStr} - 80}`;else result += sidStr;
} else result += sidStr;
}
return result;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "ObjectIdentifierValueBlock";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.value = this.toString();
object.sidArray = [];
for (let i = 0; i < this.value.length; i++) object.sidArray.push(this.value[i].toJSON());
return object;
} //**********************************************************************************
} //**************************************************************************************
/**
* @extends BaseBlock
*/
class ObjectIdentifier extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "ObjectIdentifier" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters, LocalObjectIdentifierValueBlock);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "ObjectIdentifier";
} //**********************************************************************************
}
exports.ObjectIdentifier = ObjectIdentifier; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of all string's classes
//**************************************************************************************
class LocalUtf8StringValueBlock extends LocalHexBlock(LocalBaseBlock) {
//**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Constructor for "LocalUtf8StringValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.isHexOnly = true;
this.value = ""; // String representation of decoded ArrayBuffer
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Utf8StringValueBlock";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.value = this.value;
return object;
} //**********************************************************************************
} //**************************************************************************************
/**
* @extends BaseBlock
*/
class Utf8String extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "Utf8String" class
* @param {Object} [parameters={}]
* @property {ArrayBuffer} [valueHex]
*/
constructor(parameters = {}) {
super(parameters, LocalUtf8StringValueBlock);
if ("value" in parameters) this.fromString(parameters.value);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 12; // Utf8String
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Utf8String";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHex);
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Function converting ArrayBuffer into ASN.1 internal string
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
*/
fromBuffer(inputBuffer) {
this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer));
try {
//noinspection JSDeprecatedSymbols
this.valueBlock.value = decodeURIComponent(escape(this.valueBlock.value));
} catch (ex) {
this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`);
}
} //**********************************************************************************
/**
* Function converting JavaScript string into ASN.1 internal class
* @param {!string} inputString ASN.1 BER encoded array
*/
fromString(inputString) {
//noinspection JSDeprecatedSymbols
const str = unescape(encodeURIComponent(inputString));
const strLen = str.length;
this.valueBlock.valueHex = new ArrayBuffer(strLen);
const view = new Uint8Array(this.valueBlock.valueHex);
for (let i = 0; i < strLen; i++) view[i] = str.charCodeAt(i);
this.valueBlock.value = inputString;
} //**********************************************************************************
}
exports.Utf8String = Utf8String; //**************************************************************************************
/**
* @extends LocalBaseBlock
* @extends LocalHexBlock
*/
class LocalBmpStringValueBlock extends LocalHexBlock(LocalBaseBlock) {
//**********************************************************************************
/**
* Constructor for "LocalBmpStringValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.isHexOnly = true;
this.value = "";
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "BmpStringValueBlock";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.value = this.value;
return object;
} //**********************************************************************************
} //**************************************************************************************
/**
* @extends BaseBlock
*/
class BmpString extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "BmpString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalBmpStringValueBlock);
if ("value" in parameters) this.fromString(parameters.value);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 30; // BmpString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "BmpString";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHex);
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Function converting ArrayBuffer into ASN.1 internal string
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
*/
fromBuffer(inputBuffer) {
//noinspection JSCheckFunctionSignatures
const copyBuffer = inputBuffer.slice(0);
const valueView = new Uint8Array(copyBuffer);
for (let i = 0; i < valueView.length; i += 2) {
const temp = valueView[i];
valueView[i] = valueView[i + 1];
valueView[i + 1] = temp;
}
this.valueBlock.value = String.fromCharCode.apply(null, new Uint16Array(copyBuffer));
} //**********************************************************************************
/**
* Function converting JavaScript string into ASN.1 internal class
* @param {!string} inputString ASN.1 BER encoded array
*/
fromString(inputString) {
const strLength = inputString.length;
this.valueBlock.valueHex = new ArrayBuffer(strLength * 2);
const valueHexView = new Uint8Array(this.valueBlock.valueHex);
for (let i = 0; i < strLength; i++) {
const codeBuf = (0, utils.utilToBase)(inputString.charCodeAt(i), 8);
const codeView = new Uint8Array(codeBuf);
if (codeView.length > 2) continue;
const dif = 2 - codeView.length;
for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 2 + j + dif] = codeView[j];
}
this.valueBlock.value = inputString;
} //**********************************************************************************
}
exports.BmpString = BmpString; //**************************************************************************************
class LocalUniversalStringValueBlock extends LocalHexBlock(LocalBaseBlock) {
//**********************************************************************************
/**
* Constructor for "LocalUniversalStringValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.isHexOnly = true;
this.value = "";
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "UniversalStringValueBlock";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.value = this.value;
return object;
} //**********************************************************************************
} //**************************************************************************************
/**
* @extends BaseBlock
*/
class UniversalString extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "UniversalString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalUniversalStringValueBlock);
if ("value" in parameters) this.fromString(parameters.value);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 28; // UniversalString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "UniversalString";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHex);
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Function converting ArrayBuffer into ASN.1 internal string
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
*/
fromBuffer(inputBuffer) {
//noinspection JSCheckFunctionSignatures
const copyBuffer = inputBuffer.slice(0);
const valueView = new Uint8Array(copyBuffer);
for (let i = 0; i < valueView.length; i += 4) {
valueView[i] = valueView[i + 3];
valueView[i + 1] = valueView[i + 2];
valueView[i + 2] = 0x00;
valueView[i + 3] = 0x00;
}
this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer));
} //**********************************************************************************
/**
* Function converting JavaScript string into ASN.1 internal class
* @param {!string} inputString ASN.1 BER encoded array
*/
fromString(inputString) {
const strLength = inputString.length;
this.valueBlock.valueHex = new ArrayBuffer(strLength * 4);
const valueHexView = new Uint8Array(this.valueBlock.valueHex);
for (let i = 0; i < strLength; i++) {
const codeBuf = (0, utils.utilToBase)(inputString.charCodeAt(i), 8);
const codeView = new Uint8Array(codeBuf);
if (codeView.length > 4) continue;
const dif = 4 - codeView.length;
for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 4 + j + dif] = codeView[j];
}
this.valueBlock.value = inputString;
} //**********************************************************************************
}
exports.UniversalString = UniversalString; //**************************************************************************************
class LocalSimpleStringValueBlock extends LocalHexBlock(LocalBaseBlock) {
//**********************************************************************************
/**
* Constructor for "LocalSimpleStringValueBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.value = "";
this.isHexOnly = true;
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "SimpleStringValueBlock";
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.value = this.value;
return object;
} //**********************************************************************************
} //**************************************************************************************
/**
* @extends BaseBlock
*/
class LocalSimpleStringBlock extends BaseBlock {
//**********************************************************************************
/**
* Constructor for "LocalSimpleStringBlock" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters, LocalSimpleStringValueBlock);
if ("value" in parameters) this.fromString(parameters.value);
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "SIMPLESTRING";
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHex);
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Function converting ArrayBuffer into ASN.1 internal string
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
*/
fromBuffer(inputBuffer) {
this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer));
} //**********************************************************************************
/**
* Function converting JavaScript string into ASN.1 internal class
* @param {!string} inputString ASN.1 BER encoded array
*/
fromString(inputString) {
const strLen = inputString.length;
this.valueBlock.valueHex = new ArrayBuffer(strLen);
const view = new Uint8Array(this.valueBlock.valueHex);
for (let i = 0; i < strLen; i++) view[i] = inputString.charCodeAt(i);
this.valueBlock.value = inputString;
} //**********************************************************************************
} //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class NumericString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "NumericString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 18; // NumericString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "NumericString";
} //**********************************************************************************
}
exports.NumericString = NumericString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class PrintableString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "PrintableString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 19; // PrintableString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "PrintableString";
} //**********************************************************************************
}
exports.PrintableString = PrintableString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class TeletexString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "TeletexString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 20; // TeletexString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "TeletexString";
} //**********************************************************************************
}
exports.TeletexString = TeletexString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class VideotexString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "VideotexString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 21; // VideotexString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "VideotexString";
} //**********************************************************************************
}
exports.VideotexString = VideotexString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class IA5String extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "IA5String" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 22; // IA5String
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "IA5String";
} //**********************************************************************************
}
exports.IA5String = IA5String; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class GraphicString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "GraphicString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 25; // GraphicString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "GraphicString";
} //**********************************************************************************
}
exports.GraphicString = GraphicString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class VisibleString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "VisibleString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 26; // VisibleString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "VisibleString";
} //**********************************************************************************
}
exports.VisibleString = VisibleString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class GeneralString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "GeneralString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 27; // GeneralString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "GeneralString";
} //**********************************************************************************
}
exports.GeneralString = GeneralString; //**************************************************************************************
/**
* @extends LocalSimpleStringBlock
*/
class CharacterString extends LocalSimpleStringBlock {
//**********************************************************************************
/**
* Constructor for "CharacterString" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 29; // CharacterString
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "CharacterString";
} //**********************************************************************************
}
exports.CharacterString = CharacterString; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of all date and time classes
//**************************************************************************************
/**
* @extends VisibleString
*/
class UTCTime extends VisibleString {
//**********************************************************************************
/**
* Constructor for "UTCTime" class
* @param {Object} [parameters={}]
* @property {string} [value] String representatio of the date
* @property {Date} [valueDate] JavaScript "Date" object
*/
constructor(parameters = {}) {
super(parameters);
this.year = 0;
this.month = 0;
this.day = 0;
this.hour = 0;
this.minute = 0;
this.second = 0; //region Create UTCTime from ASN.1 UTC string value
if ("value" in parameters) {
this.fromString(parameters.value);
this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length);
const view = new Uint8Array(this.valueBlock.valueHex);
for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i);
} //endregion
//region Create GeneralizedTime from JavaScript Date type
if ("valueDate" in parameters) {
this.fromDate(parameters.valueDate);
this.valueBlock.valueHex = this.toBuffer();
} //endregion
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 23; // UTCTime
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHex);
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Function converting ArrayBuffer into ASN.1 internal string
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
*/
fromBuffer(inputBuffer) {
this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer)));
} //**********************************************************************************
/**
* Function converting ASN.1 internal string into ArrayBuffer
* @returns {ArrayBuffer}
*/
toBuffer() {
const str = this.toString();
const buffer = new ArrayBuffer(str.length);
const view = new Uint8Array(buffer);
for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i);
return buffer;
} //**********************************************************************************
/**
* Function converting "Date" object into ASN.1 internal string
* @param {!Date} inputDate JavaScript "Date" object
*/
fromDate(inputDate) {
this.year = inputDate.getUTCFullYear();
this.month = inputDate.getUTCMonth() + 1;
this.day = inputDate.getUTCDate();
this.hour = inputDate.getUTCHours();
this.minute = inputDate.getUTCMinutes();
this.second = inputDate.getUTCSeconds();
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Function converting ASN.1 internal string into "Date" object
* @returns {Date}
*/
toDate() {
return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second));
} //**********************************************************************************
/**
* Function converting JavaScript string into ASN.1 internal class
* @param {!string} inputString ASN.1 BER encoded array
*/
fromString(inputString) {
//region Parse input string
const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig;
const parserArray = parser.exec(inputString);
if (parserArray === null) {
this.error = "Wrong input string for convertion";
return;
} //endregion
//region Store parsed values
const year = parseInt(parserArray[1], 10);
if (year >= 50) this.year = 1900 + year;else this.year = 2000 + year;
this.month = parseInt(parserArray[2], 10);
this.day = parseInt(parserArray[3], 10);
this.hour = parseInt(parserArray[4], 10);
this.minute = parseInt(parserArray[5], 10);
this.second = parseInt(parserArray[6], 10); //endregion
} //**********************************************************************************
/**
* Function converting ASN.1 internal class into JavaScript string
* @returns {string}
*/
toString() {
const outputArray = new Array(7);
outputArray[0] = (0, utils.padNumber)(this.year < 2000 ? this.year - 1900 : this.year - 2000, 2);
outputArray[1] = (0, utils.padNumber)(this.month, 2);
outputArray[2] = (0, utils.padNumber)(this.day, 2);
outputArray[3] = (0, utils.padNumber)(this.hour, 2);
outputArray[4] = (0, utils.padNumber)(this.minute, 2);
outputArray[5] = (0, utils.padNumber)(this.second, 2);
outputArray[6] = "Z";
return outputArray.join("");
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "UTCTime";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.year = this.year;
object.month = this.month;
object.day = this.day;
object.hour = this.hour;
object.minute = this.minute;
object.second = this.second;
return object;
} //**********************************************************************************
}
exports.UTCTime = UTCTime; //**************************************************************************************
/**
* @extends VisibleString
*/
class GeneralizedTime extends VisibleString {
//**********************************************************************************
/**
* Constructor for "GeneralizedTime" class
* @param {Object} [parameters={}]
* @property {string} [value] String representatio of the date
* @property {Date} [valueDate] JavaScript "Date" object
*/
constructor(parameters = {}) {
super(parameters);
this.year = 0;
this.month = 0;
this.day = 0;
this.hour = 0;
this.minute = 0;
this.second = 0;
this.millisecond = 0; //region Create UTCTime from ASN.1 UTC string value
if ("value" in parameters) {
this.fromString(parameters.value);
this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length);
const view = new Uint8Array(this.valueBlock.valueHex);
for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i);
} //endregion
//region Create GeneralizedTime from JavaScript Date type
if ("valueDate" in parameters) {
this.fromDate(parameters.valueDate);
this.valueBlock.valueHex = this.toBuffer();
} //endregion
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 24; // GeneralizedTime
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
if (resultOffset === -1) {
this.error = this.valueBlock.error;
return resultOffset;
}
this.fromBuffer(this.valueBlock.valueHex);
if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
return resultOffset;
} //**********************************************************************************
/**
* Function converting ArrayBuffer into ASN.1 internal string
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
*/
fromBuffer(inputBuffer) {
this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer)));
} //**********************************************************************************
/**
* Function converting ASN.1 internal string into ArrayBuffer
* @returns {ArrayBuffer}
*/
toBuffer() {
const str = this.toString();
const buffer = new ArrayBuffer(str.length);
const view = new Uint8Array(buffer);
for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i);
return buffer;
} //**********************************************************************************
/**
* Function converting "Date" object into ASN.1 internal string
* @param {!Date} inputDate JavaScript "Date" object
*/
fromDate(inputDate) {
this.year = inputDate.getUTCFullYear();
this.month = inputDate.getUTCMonth() + 1;
this.day = inputDate.getUTCDate();
this.hour = inputDate.getUTCHours();
this.minute = inputDate.getUTCMinutes();
this.second = inputDate.getUTCSeconds();
this.millisecond = inputDate.getUTCMilliseconds();
} //**********************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Function converting ASN.1 internal string into "Date" object
* @returns {Date}
*/
toDate() {
return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond));
} //**********************************************************************************
/**
* Function converting JavaScript string into ASN.1 internal class
* @param {!string} inputString ASN.1 BER encoded array
*/
fromString(inputString) {
//region Initial variables
let isUTC = false;
let timeString = "";
let dateTimeString = "";
let fractionPart = 0;
let parser;
let hourDifference = 0;
let minuteDifference = 0; //endregion
//region Convert as UTC time
if (inputString[inputString.length - 1] === "Z") {
timeString = inputString.substr(0, inputString.length - 1);
isUTC = true;
} //endregion
//region Convert as local time
else {
//noinspection JSPrimitiveTypeWrapperUsage
const number = new Number(inputString[inputString.length - 1]);
if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion");
timeString = inputString;
} //endregion
//region Check that we do not have a "+" and "-" symbols inside UTC time
if (isUTC) {
if (timeString.indexOf("+") !== -1) throw new Error("Wrong input string for convertion");
if (timeString.indexOf("-") !== -1) throw new Error("Wrong input string for convertion");
} //endregion
//region Get "UTC time difference" in case of local time
else {
let multiplier = 1;
let differencePosition = timeString.indexOf("+");
let differenceString = "";
if (differencePosition === -1) {
differencePosition = timeString.indexOf("-");
multiplier = -1;
}
if (differencePosition !== -1) {
differenceString = timeString.substr(differencePosition + 1);
timeString = timeString.substr(0, differencePosition);
if (differenceString.length !== 2 && differenceString.length !== 4) throw new Error("Wrong input string for convertion"); //noinspection JSPrimitiveTypeWrapperUsage
let number = new Number(differenceString.substr(0, 2));
if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion");
hourDifference = multiplier * number;
if (differenceString.length === 4) {
//noinspection JSPrimitiveTypeWrapperUsage
number = new Number(differenceString.substr(2, 2));
if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion");
minuteDifference = multiplier * number;
}
}
} //endregion
//region Get position of fraction point
let fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol
if (fractionPointPosition === -1) fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol
//endregion
//region Get fraction part
if (fractionPointPosition !== -1) {
//noinspection JSPrimitiveTypeWrapperUsage
const fractionPartCheck = new Number(`0${timeString.substr(fractionPointPosition)}`);
if (isNaN(fractionPartCheck.valueOf())) throw new Error("Wrong input string for convertion");
fractionPart = fractionPartCheck.valueOf();
dateTimeString = timeString.substr(0, fractionPointPosition);
} else dateTimeString = timeString; //endregion
//region Parse internal date
switch (true) {
case dateTimeString.length === 8:
// "YYYYMMDD"
parser = /(\d{4})(\d{2})(\d{2})/ig;
if (fractionPointPosition !== -1) throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point"
break;
case dateTimeString.length === 10:
// "YYYYMMDDHH"
parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig;
if (fractionPointPosition !== -1) {
let fractionResult = 60 * fractionPart;
this.minute = Math.floor(fractionResult);
fractionResult = 60 * (fractionResult - this.minute);
this.second = Math.floor(fractionResult);
fractionResult = 1000 * (fractionResult - this.second);
this.millisecond = Math.floor(fractionResult);
}
break;
case dateTimeString.length === 12:
// "YYYYMMDDHHMM"
parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
if (fractionPointPosition !== -1) {
let fractionResult = 60 * fractionPart;
this.second = Math.floor(fractionResult);
fractionResult = 1000 * (fractionResult - this.second);
this.millisecond = Math.floor(fractionResult);
}
break;
case dateTimeString.length === 14:
// "YYYYMMDDHHMMSS"
parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
if (fractionPointPosition !== -1) {
const fractionResult = 1000 * fractionPart;
this.millisecond = Math.floor(fractionResult);
}
break;
default:
throw new Error("Wrong input string for convertion");
} //endregion
//region Put parsed values at right places
const parserArray = parser.exec(dateTimeString);
if (parserArray === null) throw new Error("Wrong input string for convertion");
for (let j = 1; j < parserArray.length; j++) {
switch (j) {
case 1:
this.year = parseInt(parserArray[j], 10);
break;
case 2:
this.month = parseInt(parserArray[j], 10);
break;
case 3:
this.day = parseInt(parserArray[j], 10);
break;
case 4:
this.hour = parseInt(parserArray[j], 10) + hourDifference;
break;
case 5:
this.minute = parseInt(parserArray[j], 10) + minuteDifference;
break;
case 6:
this.second = parseInt(parserArray[j], 10);
break;
default:
throw new Error("Wrong input string for convertion");
}
} //endregion
//region Get final date
if (isUTC === false) {
const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
this.year = tempDate.getUTCFullYear();
this.month = tempDate.getUTCMonth();
this.day = tempDate.getUTCDay();
this.hour = tempDate.getUTCHours();
this.minute = tempDate.getUTCMinutes();
this.second = tempDate.getUTCSeconds();
this.millisecond = tempDate.getUTCMilliseconds();
} //endregion
} //**********************************************************************************
/**
* Function converting ASN.1 internal class into JavaScript string
* @returns {string}
*/
toString() {
const outputArray = [];
outputArray.push((0, utils.padNumber)(this.year, 4));
outputArray.push((0, utils.padNumber)(this.month, 2));
outputArray.push((0, utils.padNumber)(this.day, 2));
outputArray.push((0, utils.padNumber)(this.hour, 2));
outputArray.push((0, utils.padNumber)(this.minute, 2));
outputArray.push((0, utils.padNumber)(this.second, 2));
if (this.millisecond !== 0) {
outputArray.push(".");
outputArray.push((0, utils.padNumber)(this.millisecond, 3));
}
outputArray.push("Z");
return outputArray.join("");
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "GeneralizedTime";
} //**********************************************************************************
/**
* Convertion for the block to JSON object
* @returns {Object}
*/
toJSON() {
let object = {}; //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
try {
object = super.toJSON();
} catch (ex) {} //endregion
object.year = this.year;
object.month = this.month;
object.day = this.day;
object.hour = this.hour;
object.minute = this.minute;
object.second = this.second;
object.millisecond = this.millisecond;
return object;
} //**********************************************************************************
}
exports.GeneralizedTime = GeneralizedTime; //**************************************************************************************
/**
* @extends Utf8String
*/
class DATE extends Utf8String {
//**********************************************************************************
/**
* Constructor for "DATE" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 31; // DATE
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "DATE";
} //**********************************************************************************
}
exports.DATE = DATE; //**************************************************************************************
/**
* @extends Utf8String
*/
class TimeOfDay extends Utf8String {
//**********************************************************************************
/**
* Constructor for "TimeOfDay" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 32; // TimeOfDay
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "TimeOfDay";
} //**********************************************************************************
}
exports.TimeOfDay = TimeOfDay; //**************************************************************************************
/**
* @extends Utf8String
*/
class DateTime extends Utf8String {
//**********************************************************************************
/**
* Constructor for "DateTime" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 33; // DateTime
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "DateTime";
} //**********************************************************************************
}
exports.DateTime = DateTime; //**************************************************************************************
/**
* @extends Utf8String
*/
class Duration extends Utf8String {
//**********************************************************************************
/**
* Constructor for "Duration" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 34; // Duration
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "Duration";
} //**********************************************************************************
}
exports.Duration = Duration; //**************************************************************************************
/**
* @extends Utf8String
*/
class TIME extends Utf8String {
//**********************************************************************************
/**
* Constructor for "Time" class
* @param {Object} [parameters={}]
*/
constructor(parameters = {}) {
super(parameters);
this.idBlock.tagClass = 1; // UNIVERSAL
this.idBlock.tagNumber = 14; // Time
} //**********************************************************************************
/**
* Aux function, need to get a block name. Need to have it here for inhiritence
* @returns {string}
*/
static blockName() {
return "TIME";
} //**********************************************************************************
}
exports.TIME = TIME; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of special ASN.1 schema type Choice
//**************************************************************************************
class Choice {
//**********************************************************************************
/**
* Constructor for "Choice" class
* @param {Object} [parameters={}]
* @property {Array} [value] Array of ASN.1 types for make a choice from
* @property {boolean} [optional]
*/
constructor(parameters = {}) {
this.value = (0, utils.getParametersValue)(parameters, "value", []);
this.optional = (0, utils.getParametersValue)(parameters, "optional", false);
} //**********************************************************************************
}
exports.Choice = Choice; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of special ASN.1 schema type Any
//**************************************************************************************
class Any {
//**********************************************************************************
/**
* Constructor for "Any" class
* @param {Object} [parameters={}]
* @property {string} [name]
* @property {boolean} [optional]
*/
constructor(parameters = {}) {
this.name = (0, utils.getParametersValue)(parameters, "name", "");
this.optional = (0, utils.getParametersValue)(parameters, "optional", false);
} //**********************************************************************************
}
exports.Any = Any; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of special ASN.1 schema type Repeated
//**************************************************************************************
class Repeated {
//**********************************************************************************
/**
* Constructor for "Repeated" class
* @param {Object} [parameters={}]
* @property {string} [name]
* @property {boolean} [optional]
*/
constructor(parameters = {}) {
this.name = (0, utils.getParametersValue)(parameters, "name", "");
this.optional = (0, utils.getParametersValue)(parameters, "optional", false);
this.value = (0, utils.getParametersValue)(parameters, "value", new Any());
this.local = (0, utils.getParametersValue)(parameters, "local", false); // Could local or global array to store elements
} //**********************************************************************************
}
exports.Repeated = Repeated; //**************************************************************************************
//endregion
//**************************************************************************************
//region Declaration of special ASN.1 schema type RawData
//**************************************************************************************
/**
* @description Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer
*/
class RawData {
//**********************************************************************************
/**
* Constructor for "Repeated" class
* @param {Object} [parameters={}]
* @property {string} [name]
* @property {boolean} [optional]
*/
constructor(parameters = {}) {
this.data = (0, utils.getParametersValue)(parameters, "data", new ArrayBuffer(0));
} //**********************************************************************************
/**
* Base function for converting block from BER encoded array of bytes
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {number} Offset after least decoded byte
*/
fromBER(inputBuffer, inputOffset, inputLength) {
this.data = inputBuffer.slice(inputOffset, inputLength);
return inputOffset + inputLength;
} //**********************************************************************************
/**
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
* @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
* @returns {ArrayBuffer}
*/
toBER(sizeOnly = false) {
return this.data;
} //**********************************************************************************
}
exports.RawData = RawData; //**************************************************************************************
//endregion
//**************************************************************************************
//region Major ASN.1 BER decoding function
//**************************************************************************************
/**
* Internal library function for decoding ASN.1 BER
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
* @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
* @param {!number} inputLength Maximum length of array of bytes which can be using in this function
* @returns {{offset: number, result: Object}}
*/
function LocalFromBER(inputBuffer, inputOffset, inputLength) {
const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function
//region Local function changing a type for ASN.1 classes
function localChangeType(inputObject, newType) {
if (inputObject instanceof newType) return inputObject;
const newObject = new newType();
newObject.idBlock = inputObject.idBlock;
newObject.lenBlock = inputObject.lenBlock;
newObject.warnings = inputObject.warnings; //noinspection JSCheckFunctionSignatures
newObject.valueBeforeDecode = inputObject.valueBeforeDecode.slice(0);
return newObject;
} //endregion
//region Create a basic ASN.1 type since we need to return errors and warnings from the function
let returnObject = new BaseBlock({}, Object); //endregion
//region Basic check for parameters
if ((0, utils.checkBufferParams)(new LocalBaseBlock(), inputBuffer, inputOffset, inputLength) === false) {
returnObject.error = "Wrong input parameters";
return {
offset: -1,
result: returnObject
};
} //endregion
//region Getting Uint8Array from ArrayBuffer
const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); //endregion
//region Initial checks
if (intBuffer.length === 0) {
this.error = "Zero buffer length";
return {
offset: -1,
result: returnObject
};
} //endregion
//region Decode indentifcation block of ASN.1 BER structure
let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength);
returnObject.warnings.concat(returnObject.idBlock.warnings);
if (resultOffset === -1) {
returnObject.error = returnObject.idBlock.error;
return {
offset: -1,
result: returnObject
};
}
inputOffset = resultOffset;
inputLength -= returnObject.idBlock.blockLength; //endregion
//region Decode length block of ASN.1 BER structure
resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength);
returnObject.warnings.concat(returnObject.lenBlock.warnings);
if (resultOffset === -1) {
returnObject.error = returnObject.lenBlock.error;
return {
offset: -1,
result: returnObject
};
}
inputOffset = resultOffset;
inputLength -= returnObject.lenBlock.blockLength; //endregion
//region Check for usign indefinite length form in encoding for primitive types
if (returnObject.idBlock.isConstructed === false && returnObject.lenBlock.isIndefiniteForm === true) {
returnObject.error = "Indefinite length form used for primitive encoding form";
return {
offset: -1,
result: returnObject
};
} //endregion
//region Switch ASN.1 block type
let newASN1Type = BaseBlock;
switch (returnObject.idBlock.tagClass) {
//region UNIVERSAL
case 1:
//region Check for reserved tag numbers
if (returnObject.idBlock.tagNumber >= 37 && returnObject.idBlock.isHexOnly === false) {
returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard";
return {
offset: -1,
result: returnObject
};
} //endregion
switch (returnObject.idBlock.tagNumber) {
//region EndOfContent type
case 0:
//region Check for EndOfContent type
if (returnObject.idBlock.isConstructed === true && returnObject.lenBlock.length > 0) {
returnObject.error = "Type [UNIVERSAL 0] is reserved";
return {
offset: -1,
result: returnObject
};
} //endregion
newASN1Type = EndOfContent;
break;
//endregion
//region Boolean type
case 1:
newASN1Type = Boolean;
break;
//endregion
//region Integer type
case 2:
newASN1Type = Integer;
break;
//endregion
//region BitString type
case 3:
newASN1Type = BitString;
break;
//endregion
//region OctetString type
case 4:
newASN1Type = OctetString;
break;
//endregion
//region Null type
case 5:
newASN1Type = Null;
break;
//endregion
//region OBJECT IDENTIFIER type
case 6:
newASN1Type = ObjectIdentifier;
break;
//endregion
//region Enumerated type
case 10:
newASN1Type = Enumerated;
break;
//endregion
//region Utf8String type
case 12:
newASN1Type = Utf8String;
break;
//endregion
//region Time type
case 14:
newASN1Type = TIME;
break;
//endregion
//region ASN.1 reserved type
case 15:
returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard";
return {
offset: -1,
result: returnObject
};
//endregion
//region Sequence type
case 16:
newASN1Type = Sequence;
break;
//endregion
//region Set type
case 17:
newASN1Type = Set;
break;
//endregion
//region NumericString type
case 18:
newASN1Type = NumericString;
break;
//endregion
//region PrintableString type
case 19:
newASN1Type = PrintableString;
break;
//endregion
//region TeletexString type
case 20:
newASN1Type = TeletexString;
break;
//endregion
//region VideotexString type
case 21:
newASN1Type = VideotexString;
break;
//endregion
//region IA5String type
case 22:
newASN1Type = IA5String;
break;
//endregion
//region UTCTime type
case 23:
newASN1Type = UTCTime;
break;
//endregion
//region GeneralizedTime type
case 24:
newASN1Type = GeneralizedTime;
break;
//endregion
//region GraphicString type
case 25:
newASN1Type = GraphicString;
break;
//endregion
//region VisibleString type
case 26:
newASN1Type = VisibleString;
break;
//endregion
//region GeneralString type
case 27:
newASN1Type = GeneralString;
break;
//endregion
//region UniversalString type
case 28:
newASN1Type = UniversalString;
break;
//endregion
//region CharacterString type
case 29:
newASN1Type = CharacterString;
break;
//endregion
//region BmpString type
case 30:
newASN1Type = BmpString;
break;
//endregion
//region DATE type
case 31:
newASN1Type = DATE;
break;
//endregion
//region TimeOfDay type
case 32:
newASN1Type = TimeOfDay;
break;
//endregion
//region Date-Time type
case 33:
newASN1Type = DateTime;
break;
//endregion
//region Duration type
case 34:
newASN1Type = Duration;
break;
//endregion
//region default
default:
{
let newObject;
if (returnObject.idBlock.isConstructed === true) newObject = new Constructed();else newObject = new Primitive();
newObject.idBlock = returnObject.idBlock;
newObject.lenBlock = returnObject.lenBlock;
newObject.warnings = returnObject.warnings;
returnObject = newObject;
resultOffset = returnObject.fromBER(inputBuffer, inputOffset, inputLength);
}
//endregion
}
break;
//endregion
//region All other tag classes
case 2: // APPLICATION
case 3: // CONTEXT-SPECIFIC
case 4: // PRIVATE
default:
{
if (returnObject.idBlock.isConstructed === true) newASN1Type = Constructed;else newASN1Type = Primitive;
}
//endregion
} //endregion
//region Change type and perform BER decoding
returnObject = localChangeType(returnObject, newASN1Type);
resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm === true ? inputLength : returnObject.lenBlock.length); //endregion
//region Coping incoming buffer for entire ASN.1 block
returnObject.valueBeforeDecode = inputBuffer.slice(incomingOffset, incomingOffset + returnObject.blockLength); //endregion
return {
offset: resultOffset,
result: returnObject
};
} //**************************************************************************************
/**
* Major function for decoding ASN.1 BER array into internal library structuries
* @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array of bytes
*/
function fromBER(inputBuffer) {
if (inputBuffer.byteLength === 0) {
const result = new BaseBlock({}, Object);
result.error = "Input buffer has zero length";
return {
offset: -1,
result
};
}
return LocalFromBER(inputBuffer, 0, inputBuffer.byteLength);
} //**************************************************************************************
//endregion
//**************************************************************************************
//region Major scheme verification function
//**************************************************************************************
/**
* Compare of two ASN.1 object trees
* @param {!Object} root Root of input ASN.1 object tree
* @param {!Object} inputData Input ASN.1 object tree
* @param {!Object} inputSchema Input ASN.1 schema to compare with
* @return {{verified: boolean}|{verified:boolean, result: Object}}
*/
function compareSchema(root, inputData, inputSchema) {
//region Special case for Choice schema element type
if (inputSchema instanceof Choice) {
for (let j = 0; j < inputSchema.value.length; j++) {
const result = compareSchema(root, inputData, inputSchema.value[j]);
if (result.verified === true) {
return {
verified: true,
result: root
};
}
}
{
const _result = {
verified: false,
result: {
error: "Wrong values for Choice type"
}
};
if (inputSchema.hasOwnProperty("name")) _result.name = inputSchema.name;
return _result;
}
} //endregion
//region Special case for Any schema element type
if (inputSchema instanceof Any) {
//region Add named component of ASN.1 schema
if (inputSchema.hasOwnProperty("name")) root[inputSchema.name] = inputData; //endregion
return {
verified: true,
result: root
};
} //endregion
//region Initial check
if (root instanceof Object === false) {
return {
verified: false,
result: {
error: "Wrong root object"
}
};
}
if (inputData instanceof Object === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 data"
}
};
}
if (inputSchema instanceof Object === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
if ("idBlock" in inputSchema === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
} //endregion
//region Comparing idBlock properties in ASN.1 data and ASN.1 schema
//region Encode and decode ASN.1 schema idBlock
/// <remarks>This encoding/decoding is neccessary because could be an errors in schema definition</remarks>
if ("fromBER" in inputSchema.idBlock === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
if ("toBER" in inputSchema.idBlock === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
const encodedId = inputSchema.idBlock.toBER(false);
if (encodedId.byteLength === 0) {
return {
verified: false,
result: {
error: "Error encoding idBlock for ASN.1 schema"
}
};
}
const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength);
if (decodedOffset === -1) {
return {
verified: false,
result: {
error: "Error decoding idBlock for ASN.1 schema"
}
};
} //endregion
//region tagClass
if (inputSchema.idBlock.hasOwnProperty("tagClass") === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) {
return {
verified: false,
result: root
};
} //endregion
//region tagNumber
if (inputSchema.idBlock.hasOwnProperty("tagNumber") === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) {
return {
verified: false,
result: root
};
} //endregion
//region isConstructed
if (inputSchema.idBlock.hasOwnProperty("isConstructed") === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) {
return {
verified: false,
result: root
};
} //endregion
//region isHexOnly
if ("isHexOnly" in inputSchema.idBlock === false) // Since 'isHexOnly' is an inhirited property
{
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) {
return {
verified: false,
result: root
};
} //endregion
//region valueHex
if (inputSchema.idBlock.isHexOnly === true) {
if ("valueHex" in inputSchema.idBlock === false) // Since 'valueHex' is an inhirited property
{
return {
verified: false,
result: {
error: "Wrong ASN.1 schema"
}
};
}
const schemaView = new Uint8Array(inputSchema.idBlock.valueHex);
const asn1View = new Uint8Array(inputData.idBlock.valueHex);
if (schemaView.length !== asn1View.length) {
return {
verified: false,
result: root
};
}
for (let i = 0; i < schemaView.length; i++) {
if (schemaView[i] !== asn1View[1]) {
return {
verified: false,
result: root
};
}
}
} //endregion
//endregion
//region Add named component of ASN.1 schema
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") root[inputSchema.name] = inputData;
} //endregion
//region Getting next ASN.1 block for comparition
if (inputSchema.idBlock.isConstructed === true) {
let admission = 0;
let result = {
verified: false
};
let maxLength = inputSchema.valueBlock.value.length;
if (maxLength > 0) {
if (inputSchema.valueBlock.value[0] instanceof Repeated) maxLength = inputData.valueBlock.value.length;
} //region Special case when constructive value has no elements
if (maxLength === 0) {
return {
verified: true,
result: root
};
} //endregion
//region Special case when "inputData" has no values and "inputSchema" has all optional values
if (inputData.valueBlock.value.length === 0 && inputSchema.valueBlock.value.length !== 0) {
let _optional = true;
for (let i = 0; i < inputSchema.valueBlock.value.length; i++) _optional = _optional && (inputSchema.valueBlock.value[i].optional || false);
if (_optional === true) {
return {
verified: true,
result: root
};
} //region Delete early added name of block
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") delete root[inputSchema.name];
} //endregion
root.error = "Inconsistent object length";
return {
verified: false,
result: root
};
} //endregion
for (let i = 0; i < maxLength; i++) {
//region Special case when there is an "optional" element of ASN.1 schema at the end
if (i - admission >= inputData.valueBlock.value.length) {
if (inputSchema.valueBlock.value[i].optional === false) {
const _result = {
verified: false,
result: root
};
root.error = "Inconsistent length between ASN.1 data and schema"; //region Delete early added name of block
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") {
delete root[inputSchema.name];
_result.name = inputSchema.name;
}
} //endregion
return _result;
}
} //endregion
else {
//region Special case for Repeated type of ASN.1 schema element
if (inputSchema.valueBlock.value[0] instanceof Repeated) {
result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value);
if (result.verified === false) {
if (inputSchema.valueBlock.value[0].optional === true) admission++;else {
//region Delete early added name of block
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") delete root[inputSchema.name];
} //endregion
return result;
}
}
if ("name" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].name.length > 0) {
let arrayRoot = {};
if ("local" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].local === true) arrayRoot = inputData;else arrayRoot = root;
if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") arrayRoot[inputSchema.valueBlock.value[0].name] = [];
arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]);
}
} //endregion
else {
result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]);
if (result.verified === false) {
if (inputSchema.valueBlock.value[i].optional === true) admission++;else {
//region Delete early added name of block
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") delete root[inputSchema.name];
} //endregion
return result;
}
}
}
}
}
if (result.verified === false) // The situation may take place if last element is "optional" and verification failed
{
const _result = {
verified: false,
result: root
}; //region Delete early added name of block
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") {
delete root[inputSchema.name];
_result.name = inputSchema.name;
}
} //endregion
return _result;
}
return {
verified: true,
result: root
};
} //endregion
//region Ability to parse internal value for primitive-encoded value (value of OctetString, for example)
if ("primitiveSchema" in inputSchema && "valueHex" in inputData.valueBlock) {
//region Decoding of raw ASN.1 data
const asn1 = fromBER(inputData.valueBlock.valueHex);
if (asn1.offset === -1) {
const _result = {
verified: false,
result: asn1.result
}; //region Delete early added name of block
if (inputSchema.hasOwnProperty("name")) {
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
if (inputSchema.name !== "") {
delete root[inputSchema.name];
_result.name = inputSchema.name;
}
} //endregion
return _result;
} //endregion
return compareSchema(root, asn1.result, inputSchema.primitiveSchema);
}
return {
verified: true,
result: root
}; //endregion
} //**************************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* ASN.1 schema verification for ArrayBuffer data
* @param {!ArrayBuffer} inputBuffer Input BER-encoded ASN.1 data
* @param {!Object} inputSchema Input ASN.1 schema to verify against to
* @return {{verified: boolean}|{verified:boolean, result: Object}}
*/
function verifySchema(inputBuffer, inputSchema) {
//region Initial check
if (inputSchema instanceof Object === false) {
return {
verified: false,
result: {
error: "Wrong ASN.1 schema type"
}
};
} //endregion
//region Decoding of raw ASN.1 data
const asn1 = fromBER(inputBuffer);
if (asn1.offset === -1) {
return {
verified: false,
result: asn1.result
};
} //endregion
//region Compare ASN.1 struct with input schema
return compareSchema(asn1.result, asn1.result, inputSchema); //endregion
} //**************************************************************************************
//endregion
//**************************************************************************************
//region Major function converting JSON to ASN.1 objects
//**************************************************************************************
//noinspection JSUnusedGlobalSymbols
/**
* Converting from JSON to ASN.1 objects
* @param {string|Object} json JSON string or object to convert to ASN.1 objects
*/
function fromJSON(json) {} // TODO Implement
//**************************************************************************************
//endregion
//**************************************************************************************
});
unwrapExports(asn1);
var asn1_1 = asn1.RawData;
var asn1_2 = asn1.Repeated;
var asn1_3 = asn1.Any;
var asn1_4 = asn1.Choice;
var asn1_5 = asn1.TIME;
var asn1_6 = asn1.Duration;
var asn1_7 = asn1.DateTime;
var asn1_8 = asn1.TimeOfDay;
var asn1_9 = asn1.DATE;
var asn1_10 = asn1.GeneralizedTime;
var asn1_11 = asn1.UTCTime;
var asn1_12 = asn1.CharacterString;
var asn1_13 = asn1.GeneralString;
var asn1_14 = asn1.VisibleString;
var asn1_15 = asn1.GraphicString;
var asn1_16 = asn1.IA5String;
var asn1_17 = asn1.VideotexString;
var asn1_18 = asn1.TeletexString;
var asn1_19 = asn1.PrintableString;
var asn1_20 = asn1.NumericString;
var asn1_21 = asn1.UniversalString;
var asn1_22 = asn1.BmpString;
var asn1_23 = asn1.Utf8String;
var asn1_24 = asn1.ObjectIdentifier;
var asn1_25 = asn1.Enumerated;
var asn1_26 = asn1.Integer;
var asn1_27 = asn1.BitString;
var asn1_28 = asn1.OctetString;
var asn1_29 = asn1.Null;
var asn1_30 = asn1.Set;
var asn1_31 = asn1.Sequence;
var asn1_32 = asn1.Boolean;
var asn1_33 = asn1.EndOfContent;
var asn1_34 = asn1.Constructed;
var asn1_35 = asn1.Primitive;
var asn1_36 = asn1.BaseBlock;
var asn1_37 = asn1.fromBER;
var asn1_38 = asn1.compareSchema;
var asn1_39 = asn1.verifySchema;
var asn1_40 = asn1.fromJSON;
var build = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, '__esModule', {
value: true
});
const AsnAnyConverter = {
fromASN: value => value instanceof asn1.Null ? null : value.valueBeforeDecode,
toASN: value => {
if (value === null) {
return new asn1.Null();
}
const schema = asn1.fromBER(value);
if (schema.result.error) {
throw new Error(schema.result.error);
}
return schema.result;
}
};
const AsnIntegerConverter = {
fromASN: value => !value.valueBlock.valueDec && value.valueBlock.valueHex.byteLength > 0 ? value.valueBlock.toString() : value.valueBlock.valueDec,
toASN: value => new asn1.Integer({
value
})
};
const AsnEnumeratedConverter = {
fromASN: value => value.valueBlock.valueDec,
toASN: value => new asn1.Enumerated({
value
})
};
const AsnIntegerArrayBufferConverter = {
fromASN: value => value.valueBlock.valueHex,
toASN: value => new asn1.Integer({
valueHex: value
})
};
const AsnBitStringConverter = {
fromASN: value => value.valueBlock.valueHex,
toASN: value => new asn1.BitString({
valueHex: value
})
};
const AsnObjectIdentifierConverter = {
fromASN: value => value.valueBlock.toString(),
toASN: value => new asn1.ObjectIdentifier({
value
})
};
const AsnBooleanConverter = {
fromASN: value => value.valueBlock.value,
toASN: value => new asn1.Boolean({
value
})
};
const AsnOctetStringConverter = {
fromASN: value => value.valueBlock.valueHex,
toASN: value => new asn1.OctetString({
valueHex: value
})
};
function createStringConverter(Asn1Type) {
return {
fromASN: value => value.valueBlock.value,
toASN: value => new Asn1Type({
value
})
};
}
const AsnUtf8StringConverter = createStringConverter(asn1.Utf8String);
const AsnBmpStringConverter = createStringConverter(asn1.BmpString);
const AsnUniversalStringConverter = createStringConverter(asn1.UniversalString);
const AsnNumericStringConverter = createStringConverter(asn1.NumericString);
const AsnPrintableStringConverter = createStringConverter(asn1.PrintableString);
const AsnTeletexStringConverter = createStringConverter(asn1.TeletexString);
const AsnVideotexStringConverter = createStringConverter(asn1.VideotexString);
const AsnIA5StringConverter = createStringConverter(asn1.IA5String);
const AsnGraphicStringConverter = createStringConverter(asn1.GraphicString);
const AsnVisibleStringConverter = createStringConverter(asn1.VisibleString);
const AsnGeneralStringConverter = createStringConverter(asn1.GeneralString);
const AsnCharacterStringConverter = createStringConverter(asn1.CharacterString);
const AsnUTCTimeConverter = {
fromASN: value => value.toDate(),
toASN: value => new asn1.UTCTime({
valueDate: value
})
};
const AsnGeneralizedTimeConverter = {
fromASN: value => value.toDate(),
toASN: value => new asn1.GeneralizedTime({
valueDate: value
})
};
var defaultConverters =
/*#__PURE__*/
Object.freeze({
AsnAnyConverter: AsnAnyConverter,
AsnIntegerConverter: AsnIntegerConverter,
AsnEnumeratedConverter: AsnEnumeratedConverter,
AsnIntegerArrayBufferConverter: AsnIntegerArrayBufferConverter,
AsnBitStringConverter: AsnBitStringConverter,
AsnObjectIdentifierConverter: AsnObjectIdentifierConverter,
AsnBooleanConverter: AsnBooleanConverter,
AsnOctetStringConverter: AsnOctetStringConverter,
AsnUtf8StringConverter: AsnUtf8StringConverter,
AsnBmpStringConverter: AsnBmpStringConverter,
AsnUniversalStringConverter: AsnUniversalStringConverter,
AsnNumericStringConverter: AsnNumericStringConverter,
AsnPrintableStringConverter: AsnPrintableStringConverter,
AsnTeletexStringConverter: AsnTeletexStringConverter,
AsnVideotexStringConverter: AsnVideotexStringConverter,
AsnIA5StringConverter: AsnIA5StringConverter,
AsnGraphicStringConverter: AsnGraphicStringConverter,
AsnVisibleStringConverter: AsnVisibleStringConverter,
AsnGeneralStringConverter: AsnGeneralStringConverter,
AsnCharacterStringConverter: AsnCharacterStringConverter,
AsnUTCTimeConverter: AsnUTCTimeConverter,
AsnGeneralizedTimeConverter: AsnGeneralizedTimeConverter
});
(function (AsnTypeTypes) {
AsnTypeTypes[AsnTypeTypes["Sequence"] = 0] = "Sequence";
AsnTypeTypes[AsnTypeTypes["Set"] = 1] = "Set";
AsnTypeTypes[AsnTypeTypes["Choice"] = 2] = "Choice";
})(exports.AsnTypeTypes || (exports.AsnTypeTypes = {}));
(function (AsnPropTypes) {
AsnPropTypes[AsnPropTypes["Any"] = 0] = "Any";
AsnPropTypes[AsnPropTypes["Boolean"] = 1] = "Boolean";
AsnPropTypes[AsnPropTypes["OctetString"] = 2] = "OctetString";
AsnPropTypes[AsnPropTypes["BitString"] = 3] = "BitString";
AsnPropTypes[AsnPropTypes["Integer"] = 4] = "Integer";
AsnPropTypes[AsnPropTypes["Enumerated"] = 5] = "Enumerated";
AsnPropTypes[AsnPropTypes["ObjectIdentifier"] = 6] = "ObjectIdentifier";
AsnPropTypes[AsnPropTypes["Utf8String"] = 7] = "Utf8String";
AsnPropTypes[AsnPropTypes["BmpString"] = 8] = "BmpString";
AsnPropTypes[AsnPropTypes["UniversalString"] = 9] = "UniversalString";
AsnPropTypes[AsnPropTypes["NumericString"] = 10] = "NumericString";
AsnPropTypes[AsnPropTypes["PrintableString"] = 11] = "PrintableString";
AsnPropTypes[AsnPropTypes["TeletexString"] = 12] = "TeletexString";
AsnPropTypes[AsnPropTypes["VideotexString"] = 13] = "VideotexString";
AsnPropTypes[AsnPropTypes["IA5String"] = 14] = "IA5String";
AsnPropTypes[AsnPropTypes["GraphicString"] = 15] = "GraphicString";
AsnPropTypes[AsnPropTypes["VisibleString"] = 16] = "VisibleString";
AsnPropTypes[AsnPropTypes["GeneralString"] = 17] = "GeneralString";
AsnPropTypes[AsnPropTypes["CharacterString"] = 18] = "CharacterString";
AsnPropTypes[AsnPropTypes["UTCTime"] = 19] = "UTCTime";
AsnPropTypes[AsnPropTypes["GeneralizedTime"] = 20] = "GeneralizedTime";
AsnPropTypes[AsnPropTypes["DATE"] = 21] = "DATE";
AsnPropTypes[AsnPropTypes["TimeOfDay"] = 22] = "TimeOfDay";
AsnPropTypes[AsnPropTypes["DateTime"] = 23] = "DateTime";
AsnPropTypes[AsnPropTypes["Duration"] = 24] = "Duration";
AsnPropTypes[AsnPropTypes["TIME"] = 25] = "TIME";
AsnPropTypes[AsnPropTypes["Null"] = 26] = "Null";
})(exports.AsnPropTypes || (exports.AsnPropTypes = {}));
const asn1$1 = asn1;
class AsnSchemaStorage {
constructor() {
this.items = new Map();
}
has(target) {
return this.items.has(target);
}
get(target) {
const schema = this.items.get(target);
if (!schema) {
throw new Error("Cannot get schema for current target");
}
return schema;
}
cache(target) {
const schema = this.get(target);
if (!schema.schema) {
schema.schema = this.create(target, true);
}
}
createDefault(target) {
const schema = {
type: exports.AsnTypeTypes.Sequence,
items: {}
};
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.items = Object.assign({}, schema.items, parentSchema.items);
}
return schema;
}
create(target, useNames) {
const schema = this.items.get(target) || this.createDefault(target);
const asn1Value = [];
for (const key in schema.items) {
const item = schema.items[key];
const name = useNames ? key : "";
let asn1Item;
if (typeof item.type === "number") {
const Asn1TypeName = exports.AsnPropTypes[item.type];
const Asn1Type = asn1$1[Asn1TypeName];
if (!Asn1Type) {
throw new Error(`Cannot get ASN1 class by name '${Asn1TypeName}'`);
}
asn1Item = new Asn1Type({
name
});
} else {
asn1Item = new asn1$1.Any({
name
});
}
const optional = !!item.optional || item.defaultValue !== undefined;
if (item.repeated) {
asn1Item.name = "";
asn1Item = new asn1$1.Repeated({
name,
value: asn1Item
});
}
if (item.context !== null && item.context !== undefined) {
if (item.implicit) {
if (typeof item.type === "number") {
asn1Value.push(new asn1$1.Primitive({
name,
optional,
idBlock: {
tagClass: 3,
tagNumber: item.context
}
}));
} else {
this.cache(item.type);
const value = this.get(item.type).schema.valueBlock.value;
asn1Value.push(new asn1$1.Constructed({
name,
optional,
idBlock: {
tagClass: 3,
tagNumber: item.context
},
value
}));
}
} else {
asn1Value.push(new asn1$1.Constructed({
optional,
idBlock: {
tagClass: 3,
tagNumber: item.context
},
value: [asn1Item]
}));
}
} else {
asn1Item.optional = optional;
asn1Value.push(asn1Item);
}
}
switch (schema.type) {
case exports.AsnTypeTypes.Sequence:
return new asn1$1.Sequence({
value: asn1Value,
name: ""
});
case exports.AsnTypeTypes.Set:
return new asn1$1.Set({
value: asn1Value,
name: ""
});
case exports.AsnTypeTypes.Choice:
return new asn1$1.Choice({
value: asn1Value,
name: ""
});
default:
throw new Error(`Unsupported ASN1 type in use`);
}
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = target.__proto__;
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
const schemaStorage = new AsnSchemaStorage();
const AsnType = options => target => {
const schema = schemaStorage.get(target);
Object.assign(schema, options);
};
const AsnProp = options => (target, propertyKey) => {
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.createDefault(target.constructor);
schemaStorage.set(target.constructor, schema);
} else {
schema = schemaStorage.get(target.constructor);
}
const copyOptions = Object.assign({}, options);
if (typeof copyOptions.type === "number" && !copyOptions.converter) {
const converterName = `Asn${exports.AsnPropTypes[options.type]}Converter`;
const defaultConverter = defaultConverters[converterName];
if (!defaultConverter) {
throw new Error(`Cannot get '${converterName}' for property '${propertyKey}' of ${target.constructor.name}`);
}
copyOptions.converter = defaultConverter;
}
schema.items[propertyKey] = copyOptions;
};
function isConvertible(target) {
if (target && target.prototype) {
if (target.prototype.toASN && target.prototype.fromASN) {
return true;
} else {
return isConvertible(target.prototype);
}
} else {
return !!(target && target.toASN && target.fromASN);
}
}
const asn1$2 = asn1;
class AsnParser {
static parse(data, target, obj) {
let buf;
if (data instanceof ArrayBuffer) {
buf = data;
} else if (typeof Buffer !== undefined && Buffer.isBuffer(data)) {
buf = new Uint8Array(data).buffer;
} else if (ArrayBuffer.isView(data)) {
buf = data.buffer;
} else {
throw new TypeError("Wrong type of 'data' argument");
}
const asn1Parsed = asn1$2.fromBER(buf);
if (asn1Parsed.result.error) {
throw new Error(asn1Parsed.result.error);
}
const res = this.fromASN(asn1Parsed.result, target, obj);
return res;
}
static fromASN(asn1Schema, target, obj) {
if (isConvertible(target)) {
const value = obj || new target();
return value.fromASN(asn1Schema);
}
const schema = schemaStorage.get(target);
schemaStorage.cache(target);
let targetSchema = schema.schema;
if (asn1Schema.constructor === asn1$2.Constructed && schema.type !== exports.AsnTypeTypes.Choice) {
targetSchema = new asn1$2.Constructed({
idBlock: {
tagClass: 3,
tagNumber: asn1Schema.idBlock.tagNumber
},
value: schema.schema.valueBlock.value
});
for (const key in schema.items) {
delete asn1Schema[key];
}
}
const asn1ComparedSchema = asn1$2.compareSchema(asn1Schema, asn1Schema, targetSchema);
if (!asn1ComparedSchema.verified) {
throw new Error(`Data does not match to ${target.name} ASN1 schema. ${asn1ComparedSchema.result.error}`);
}
const res = obj || new target();
for (const key in schema.items) {
if (!asn1Schema[key]) {
continue;
}
const schemaItem = schema.items[key];
if (typeof schemaItem.type === "number") {
const converter = schemaItem.converter;
if (!converter) {
throw new Error("Converter is empty");
}
if (schemaItem.repeated) {
res[key] = Array.from(asn1Schema[key], element => converter.fromASN(element));
} else {
let value = asn1Schema[key];
if (schemaItem.implicit) {
const Asn1TypeName = exports.AsnPropTypes[schemaItem.type];
const Asn1Type = asn1$2[Asn1TypeName];
if (!Asn1Type) {
throw new Error(`Cannot get '${Asn1TypeName}' class from asn1js module`);
}
const newItem = new Asn1Type();
newItem.valueBlock = value.valueBlock;
value = asn1$2.fromBER(newItem.toBER(false)).result;
}
res[key] = converter.fromASN(value);
}
} else {
if (schemaItem.repeated) {
res[key] = Array.from(asn1Schema[key], element => this.fromASN(element, schemaItem.type));
} else {
res[key] = this.fromASN(asn1Schema[key], schemaItem.type);
}
}
}
res._cache = {
asn1: asn1Schema
};
return res;
}
}
const asn1$3 = asn1;
class AsnSerializer {
static serialize(obj) {
return this.toASN(obj).toBER(false);
}
static toASN(obj) {
if (obj && isConvertible(obj.constructor)) {
return obj.toASN();
}
const target = obj.constructor;
const schema = schemaStorage.get(target);
schemaStorage.cache(target);
let asn1Value = [];
for (const key in schema.items) {
const item = schema.items[key];
const objProp = obj[key];
if (objProp === undefined || item.defaultValue === objProp) {
continue;
}
let asn1Item;
if (typeof item.type === "number") {
const converter = item.converter;
if (!converter) {
throw new Error(`Property '${key}' doesn't have converter for type ${exports.AsnPropTypes[item.type]} in schema '${target.name}'`);
}
if (item.repeated) {
asn1Item = Array.from(objProp, element => converter.toASN(element));
} else {
asn1Item = converter.toASN(objProp);
}
} else {
if (item.repeated) {
asn1Item = Array.from(objProp, element => this.toASN(element));
} else {
asn1Item = this.toASN(objProp);
}
}
if (item.context !== null && item.context !== undefined) {
if (item.implicit) {
if (typeof item.type === "number") {
const value = {};
value.valueHex = asn1Item.valueBlock.toBER();
asn1Value.push(new asn1$3.Primitive(_objectSpread({
optional: item.optional,
idBlock: {
tagClass: 3,
tagNumber: item.context
}
}, value)));
} else {
asn1Value.push(new asn1$3.Constructed({
optional: item.optional,
idBlock: {
tagClass: 3,
tagNumber: item.context
},
value: asn1Item.valueBlock.value
}));
}
} else {
asn1Value.push(new asn1$3.Constructed({
optional: item.optional,
idBlock: {
tagClass: 3,
tagNumber: item.context
},
value: [asn1Item]
}));
}
} else if (item.repeated) {
asn1Value = asn1Value.concat(asn1Item);
} else {
asn1Value.push(asn1Item);
}
}
let asnSchema;
switch (schema.type) {
case exports.AsnTypeTypes.Sequence:
asnSchema = new asn1$3.Sequence({
value: asn1Value
});
break;
case exports.AsnTypeTypes.Set:
asnSchema = new asn1$3.Set({
value: asn1Value
});
break;
case exports.AsnTypeTypes.Choice:
if (!asn1Value[0]) {
throw new Error(`Schema '${target.name}' has wrong data. Choice cannot be empty.`);
}
asnSchema = asn1Value[0];
break;
}
return asnSchema;
}
}
exports.AsnProp = AsnProp;
exports.AsnType = AsnType;
exports.AsnParser = AsnParser;
exports.AsnSerializer = AsnSerializer;
exports.AsnAnyConverter = AsnAnyConverter;
exports.AsnIntegerConverter = AsnIntegerConverter;
exports.AsnEnumeratedConverter = AsnEnumeratedConverter;
exports.AsnIntegerArrayBufferConverter = AsnIntegerArrayBufferConverter;
exports.AsnBitStringConverter = AsnBitStringConverter;
exports.AsnObjectIdentifierConverter = AsnObjectIdentifierConverter;
exports.AsnBooleanConverter = AsnBooleanConverter;
exports.AsnOctetStringConverter = AsnOctetStringConverter;
exports.AsnUtf8StringConverter = AsnUtf8StringConverter;
exports.AsnBmpStringConverter = AsnBmpStringConverter;
exports.AsnUniversalStringConverter = AsnUniversalStringConverter;
exports.AsnNumericStringConverter = AsnNumericStringConverter;
exports.AsnPrintableStringConverter = AsnPrintableStringConverter;
exports.AsnTeletexStringConverter = AsnTeletexStringConverter;
exports.AsnVideotexStringConverter = AsnVideotexStringConverter;
exports.AsnIA5StringConverter = AsnIA5StringConverter;
exports.AsnGraphicStringConverter = AsnGraphicStringConverter;
exports.AsnVisibleStringConverter = AsnVisibleStringConverter;
exports.AsnGeneralStringConverter = AsnGeneralStringConverter;
exports.AsnCharacterStringConverter = AsnCharacterStringConverter;
exports.AsnUTCTimeConverter = AsnUTCTimeConverter;
exports.AsnGeneralizedTimeConverter = AsnGeneralizedTimeConverter;
});
unwrapExports(build);
var build_1 = build.AsnTypeTypes;
var build_2 = build.AsnPropTypes;
var build_3 = build.AsnProp;
var build_4 = build.AsnType;
var build_5 = build.AsnParser;
var build_6 = build.AsnSerializer;
var build_7 = build.AsnAnyConverter;
var build_8 = build.AsnIntegerConverter;
var build_9 = build.AsnEnumeratedConverter;
var build_10 = build.AsnIntegerArrayBufferConverter;
var build_11 = build.AsnBitStringConverter;
var build_12 = build.AsnObjectIdentifierConverter;
var build_13 = build.AsnBooleanConverter;
var build_14 = build.AsnOctetStringConverter;
var build_15 = build.AsnUtf8StringConverter;
var build_16 = build.AsnBmpStringConverter;
var build_17 = build.AsnUniversalStringConverter;
var build_18 = build.AsnNumericStringConverter;
var build_19 = build.AsnPrintableStringConverter;
var build_20 = build.AsnTeletexStringConverter;
var build_21 = build.AsnVideotexStringConverter;
var build_22 = build.AsnIA5StringConverter;
var build_23 = build.AsnGraphicStringConverter;
var build_24 = build.AsnVisibleStringConverter;
var build_25 = build.AsnGeneralStringConverter;
var build_26 = build.AsnCharacterStringConverter;
var build_27 = build.AsnUTCTimeConverter;
var build_28 = build.AsnGeneralizedTimeConverter;
var build$1 = createCommonjsModule(function (module, exports) {
Object.defineProperty(exports, '__esModule', {
value: true
});
class JsonError extends Error {
constructor(message, innerError) {
super(innerError ? `${message}. See the inner exception for more details.` : message);
this.message = message;
this.innerError = innerError;
}
}
class TransformError extends JsonError {
constructor(schema, message, innerError) {
super(message, innerError);
this.schema = schema;
}
}
class ParserError extends TransformError {
constructor(schema, message, innerError) {
super(schema, `JSON doesn't match to '${schema.target.name}' schema. ${message}`, innerError);
}
}
class ValidationError extends JsonError {}
class SerializerError extends JsonError {
constructor(schemaName, message, innerError) {
super(`Cannot serialize by '${schemaName}' schema. ${message}`, innerError);
this.schemaName = schemaName;
}
}
class KeyError extends ParserError {
constructor(schema, keys, errors = {}) {
super(schema, "Some keys doesn't match to schema");
this.keys = keys;
this.errors = errors;
}
}
(function (JsonPropTypes) {
JsonPropTypes[JsonPropTypes["Any"] = 0] = "Any";
JsonPropTypes[JsonPropTypes["Boolean"] = 1] = "Boolean";
JsonPropTypes[JsonPropTypes["Number"] = 2] = "Number";
JsonPropTypes[JsonPropTypes["String"] = 3] = "String";
})(exports.JsonPropTypes || (exports.JsonPropTypes = {}));
function checkType(value, type) {
switch (type) {
case exports.JsonPropTypes.Boolean:
return typeof value === "boolean";
case exports.JsonPropTypes.Number:
return typeof value === "number";
case exports.JsonPropTypes.String:
return typeof value === "string";
}
return true;
}
function throwIfTypeIsWrong(value, type) {
if (!checkType(value, type)) {
throw new TypeError(`Value must be ${exports.JsonPropTypes[type]}`);
}
}
function isConvertible(target) {
if (target && target.prototype) {
if (target.prototype.toJSON && target.prototype.fromJSON) {
return true;
} else {
return isConvertible(target.prototype);
}
} else {
return !!(target && target.toJSON && target.fromJSON);
}
}
class JsonSchemaStorage {
constructor() {
this.items = new Map();
}
has(target) {
return this.items.has(target) || !!this.findParentSchema(target);
}
get(target) {
const schema = this.items.get(target) || this.findParentSchema(target);
if (!schema) {
throw new Error("Cannot get schema for current target");
}
return schema;
}
create(target) {
const schema = {
names: {}
};
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.names = {};
for (const name in parentSchema.names) {
schema.names[name] = Object.assign({}, parentSchema.names[name]);
}
}
schema.target = target;
return schema;
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = target.__proto__;
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
const DEFAULT_SCHEMA = "default";
const schemaStorage = new JsonSchemaStorage();
class PatternValidation {
constructor(pattern) {
this.pattern = new RegExp(pattern);
}
validate(value) {
const pattern = new RegExp(this.pattern.source, this.pattern.flags);
if (typeof value !== "string") {
throw new ValidationError("Incoming value must be string");
}
if (!pattern.exec(value)) {
throw new ValidationError(`Value doesn't match to pattern '${pattern.toString()}'`);
}
}
}
class InclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.Number);
if (!(this.min <= value && value <= this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason [${min},${max}]`);
}
}
}
class ExclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.Number);
if (!(this.min < value && value < this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason (${min},${max})`);
}
}
}
class LengthValidation {
constructor(length, minLength, maxLength) {
this.length = length;
this.minLength = minLength;
this.maxLength = maxLength;
}
validate(value) {
if (this.length !== undefined) {
if (value.length !== this.length) {
throw new ValidationError(`Value length must be exactly ${this.length}.`);
}
return;
}
if (this.minLength !== undefined) {
if (value.length < this.minLength) {
throw new ValidationError(`Value length must be more than ${this.minLength}.`);
}
}
if (this.maxLength !== undefined) {
if (value.length > this.maxLength) {
throw new ValidationError(`Value length must be less than ${this.maxLength}.`);
}
}
}
}
class EnumerationValidation {
constructor(enumeration) {
this.enumeration = enumeration;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.String);
if (!this.enumeration.includes(value)) {
throw new ValidationError(`Value must be one of ${this.enumeration.map(v => `'${v}'`).join(", ")}`);
}
}
}
class JsonTransform {
static checkValues(data, schemaItem) {
const values = Array.isArray(data) ? data : [data];
for (const value of values) {
for (const validation of schemaItem.validations) {
if (validation instanceof LengthValidation && schemaItem.repeated) {
validation.validate(data);
} else {
validation.validate(value);
}
}
}
}
static checkTypes(value, schemaItem) {
if (schemaItem.repeated && !Array.isArray(value)) {
throw new TypeError("Value must be Array");
}
if (typeof schemaItem.type === "number") {
const values = Array.isArray(value) ? value : [value];
for (const v of values) {
throwIfTypeIsWrong(v, schemaItem.type);
}
}
}
static getSchemaByName(schema, name = DEFAULT_SCHEMA) {
return _objectSpread({}, schema.names[DEFAULT_SCHEMA], schema.names[name]);
}
}
class JsonSerializer extends JsonTransform {
static serialize(obj, options, replacer, space) {
const json = this.toJSON(obj, options);
return JSON.stringify(json, replacer, space);
}
static toJSON(obj, options = {}) {
let res;
let targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
if (isConvertible(obj)) {
return obj.toJSON();
}
if (Array.isArray(obj)) {
res = [];
for (const item of obj) {
res.push(this.toJSON(item, options));
}
} else if (typeof obj === "object") {
if (targetSchema && !schemaStorage.has(targetSchema)) {
throw new JsonError("Cannot get schema for `targetSchema` param");
}
targetSchema = targetSchema || obj.constructor;
if (schemaStorage.has(targetSchema)) {
const schema = schemaStorage.get(targetSchema);
res = {};
const namedSchema = this.getSchemaByName(schema, schemaName);
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const objItem = obj[key];
let value;
if (item.optional && objItem === undefined || item.defaultValue !== undefined && objItem === item.defaultValue) {
continue;
}
if (!item.optional && objItem === undefined) {
throw new SerializerError(targetSchema.name, `Property '${key}' is required.`);
}
if (typeof item.type === "number") {
if (item.converter) {
if (item.repeated) {
value = objItem.map(el => item.converter.toJSON(el, obj));
} else {
value = item.converter.toJSON(objItem, obj);
}
} else {
value = objItem;
}
} else {
if (item.repeated) {
value = objItem.map(el => this.toJSON(el, {
schemaName
}));
} else {
value = this.toJSON(objItem, {
schemaName
});
}
}
this.checkTypes(value, item);
this.checkValues(value, item);
res[item.name || key] = value;
} catch (e) {
if (e instanceof SerializerError) {
throw e;
} else {
throw new SerializerError(schema.target.name, `Property '${key}' is wrong. ${e.message}`, e);
}
}
}
} else {
res = {};
for (const key in obj) {
res[key] = this.toJSON(obj[key], {
schemaName
});
}
}
} else {
res = obj;
}
return res;
}
}
class JsonParser extends JsonTransform {
static parse(data, options) {
const obj = JSON.parse(data);
return this.fromJSON(obj, options);
}
static fromJSON(target, options) {
const targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
const obj = new targetSchema();
if (isConvertible(obj)) {
return obj.fromJSON(target);
}
const schema = schemaStorage.get(targetSchema);
const namedSchema = this.getSchemaByName(schema, schemaName);
const keyErrors = {};
if (options.strictProperty && !Array.isArray(target)) {
JsonParser.checkStrictProperty(target, namedSchema, schema);
}
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const name = item.name || key;
const value = target[name];
if (value === undefined && (item.optional || item.defaultValue !== undefined)) {
continue;
}
if (!item.optional && value === undefined) {
throw new ParserError(schema, `Property '${name}' is required.`);
}
this.checkTypes(value, item);
this.checkValues(value, item);
if (typeof item.type === "number") {
if (item.converter) {
if (item.repeated) {
obj[key] = value.map(el => item.converter.fromJSON(el, obj));
} else {
obj[key] = item.converter.fromJSON(value, obj);
}
} else {
obj[key] = value;
}
} else {
const newOptions = _objectSpread({}, options, {
targetSchema: item.type,
schemaName
});
if (item.repeated) {
obj[key] = value.map(el => this.fromJSON(el, newOptions));
} else {
obj[key] = this.fromJSON(value, newOptions);
}
}
} catch (e) {
if (!(e instanceof ParserError)) {
e = new ParserError(schema, `Property '${key}' is wrong. ${e.message}`, e);
}
if (options.strictAllKeys) {
keyErrors[key] = e;
} else {
throw e;
}
}
}
const keys = Object.keys(keyErrors);
if (keys.length) {
throw new KeyError(schema, keys, keyErrors);
}
return obj;
}
static checkStrictProperty(target, namedSchema, schema) {
const jsonProps = Object.keys(target);
const schemaProps = Object.keys(namedSchema);
const keys = [];
for (const key of jsonProps) {
if (schemaProps.indexOf(key) === -1) {
keys.push(key);
}
}
if (keys.length) {
throw new KeyError(schema, keys);
}
}
}
function getValidations(item) {
const validations = [];
if (item.pattern) {
validations.push(new PatternValidation(item.pattern));
}
if (item.type === exports.JsonPropTypes.Number || item.type === exports.JsonPropTypes.Any) {
if (item.minInclusive !== undefined || item.maxInclusive !== undefined) {
validations.push(new InclusiveValidation(item.minInclusive, item.maxInclusive));
}
if (item.minExclusive !== undefined || item.maxExclusive !== undefined) {
validations.push(new ExclusiveValidation(item.minExclusive, item.maxExclusive));
}
if (item.enumeration !== undefined) {
validations.push(new EnumerationValidation(item.enumeration));
}
}
if (item.type === exports.JsonPropTypes.String || item.repeated || item.type === exports.JsonPropTypes.Any) {
if (item.length !== undefined || item.minLength !== undefined || item.maxLength !== undefined) {
validations.push(new LengthValidation(item.length, item.minLength, item.maxLength));
}
}
return validations;
}
const JsonProp = (options = {}) => (target, propertyKey) => {
const errorMessage = `Cannot set type for ${propertyKey} property of ${target.constructor.name} schema`;
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
} else {
schema = schemaStorage.get(target.constructor);
if (schema.target !== target.constructor) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
}
const defaultSchema = {
type: exports.JsonPropTypes.Any,
validations: []
};
const copyOptions = Object.assign(defaultSchema, options);
copyOptions.validations = getValidations(copyOptions);
if (typeof copyOptions.type !== "number") {
if (!schemaStorage.has(copyOptions.type) && !isConvertible(copyOptions.type)) {
throw new Error(`${errorMessage}. Assigning type doesn't have schema.`);
}
}
let schemaNames;
if (Array.isArray(options.schema)) {
schemaNames = options.schema;
} else {
schemaNames = [options.schema || DEFAULT_SCHEMA];
}
for (const schemaName of schemaNames) {
if (!schema.names[schemaName]) {
schema.names[schemaName] = {};
}
const namedSchema = schema.names[schemaName];
namedSchema[propertyKey] = copyOptions;
}
};
exports.JsonSerializer = JsonSerializer;
exports.JsonParser = JsonParser;
exports.JsonProp = JsonProp;
});
unwrapExports(build$1);
var build_1$1 = build$1.JsonPropTypes;
var build_2$1 = build$1.JsonSerializer;
var build_3$1 = build$1.JsonParser;
var build_4$1 = build$1.JsonProp;
let ObjectIdentifier = class ObjectIdentifier {
constructor(value) {
if (value) {
this.value = value;
}
}
};
__decorate([build_3({
type: build_2.ObjectIdentifier
})], ObjectIdentifier.prototype, "value", void 0);
ObjectIdentifier = __decorate([build_4({
type: build_1.Choice
})], ObjectIdentifier);
class AlgorithmIdentifier {
constructor(params) {
Object.assign(this, params);
}
}
__decorate([build_3({
type: build_2.ObjectIdentifier
})], AlgorithmIdentifier.prototype, "algorithm", void 0);
__decorate([build_3({
type: build_2.Any,
optional: true
})], AlgorithmIdentifier.prototype, "parameters", void 0);
class PrivateKeyInfo {
constructor() {
this.version = 0;
this.privateKeyAlgorithm = new AlgorithmIdentifier();
this.privateKey = new ArrayBuffer(0);
}
}
__decorate([build_3({
type: build_2.Integer
})], PrivateKeyInfo.prototype, "version", void 0);
__decorate([build_3({
type: AlgorithmIdentifier
})], PrivateKeyInfo.prototype, "privateKeyAlgorithm", void 0);
__decorate([build_3({
type: build_2.OctetString
})], PrivateKeyInfo.prototype, "privateKey", void 0);
__decorate([build_3({
type: build_2.Any,
optional: true
})], PrivateKeyInfo.prototype, "attributes", void 0);
class PublicKeyInfo {
constructor() {
this.publicKeyAlgorithm = new AlgorithmIdentifier();
this.publicKey = new ArrayBuffer(0);
}
}
__decorate([build_3({
type: AlgorithmIdentifier
})], PublicKeyInfo.prototype, "publicKeyAlgorithm", void 0);
__decorate([build_3({
type: build_2.BitString
})], PublicKeyInfo.prototype, "publicKey", void 0);
const JsonBase64UrlArrayBufferConverter = {
fromJSON: value => Convert.FromBase64Url(value),
toJSON: value => Convert.ToBase64Url(new Uint8Array(value))
};
var Browser;
(function (Browser) {
Browser["Unknown"] = "Unknown";
Browser["IE"] = "Internet Explorer";
Browser["Safari"] = "Safari";
Browser["Edge"] = "Edge";
Browser["Chrome"] = "Chrome";
Browser["Firefox"] = "Firefox Mozilla";
Browser["Mobile"] = "Mobile";
})(Browser || (Browser = {}));
function BrowserInfo() {
const res = {
name: Browser.Unknown,
version: "0"
};
const userAgent = window.navigator.userAgent;
let reg;
if (reg = /edge\/([\d\.]+)/i.exec(userAgent)) {
res.name = Browser.Edge;
res.version = reg[1];
} else if (/msie/i.test(userAgent)) {
res.name = Browser.IE;
res.version = /msie ([\d\.]+)/i.exec(userAgent)[1];
} else if (/Trident/i.test(userAgent)) {
res.name = Browser.IE;
res.version = /rv:([\d\.]+)/i.exec(userAgent)[1];
} else if (/chrome/i.test(userAgent)) {
res.name = Browser.Chrome;
res.version = /chrome\/([\d\.]+)/i.exec(userAgent)[1];
} else if (/firefox/i.test(userAgent)) {
res.name = Browser.Firefox;
res.version = /firefox\/([\d\.]+)/i.exec(userAgent)[1];
} else if (/mobile/i.test(userAgent)) {
res.name = Browser.Mobile;
res.version = /mobile\/([\w]+)/i.exec(userAgent)[1];
} else if (/safari/i.test(userAgent)) {
res.name = Browser.Safari;
res.version = /version\/([\d\.]+)/i.exec(userAgent)[1];
}
return res;
}
function concat(...buf) {
const res = new Uint8Array(buf.map(item => item.length).reduce((prev, cur) => prev + cur));
let offset = 0;
buf.forEach((item, index) => {
for (let i = 0; i < item.length; i++) {
res[offset + i] = item[i];
}
offset += item.length;
});
return res;
}
const AsnIntegerArrayBufferConverter = {
fromASN: value => {
const valueHex = value.valueBlock.valueHex;
return !new Uint8Array(valueHex)[0] ? value.valueBlock.valueHex.slice(1) : value.valueBlock.valueHex;
},
toASN: value => {
const valueHex = new Uint8Array(value)[0] > 127 ? concat(new Uint8Array([0]), new Uint8Array(value)) : new Uint8Array(value);
return new asn1_26({
valueHex: new Uint8Array(valueHex).buffer
});
}
};
class RsaPrivateKey {
constructor() {
this.version = 0;
this.modulus = new ArrayBuffer(0);
this.publicExponent = new ArrayBuffer(0);
this.privateExponent = new ArrayBuffer(0);
this.prime1 = new ArrayBuffer(0);
this.prime2 = new ArrayBuffer(0);
this.exponent1 = new ArrayBuffer(0);
this.exponent2 = new ArrayBuffer(0);
this.coefficient = new ArrayBuffer(0);
}
}
__decorate([build_3({
type: build_2.Integer,
converter: build_8
})], RsaPrivateKey.prototype, "version", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "n",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "modulus", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "e",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "publicExponent", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "d",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "privateExponent", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "p",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "prime1", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "q",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "prime2", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "dp",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "exponent1", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "dq",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "exponent2", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "qi",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPrivateKey.prototype, "coefficient", void 0);
__decorate([build_3({
type: build_2.Any,
optional: true
})], RsaPrivateKey.prototype, "otherPrimeInfos", void 0);
class RsaPublicKey {
constructor() {
this.modulus = new ArrayBuffer(0);
this.publicExponent = new ArrayBuffer(0);
}
}
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "n",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPublicKey.prototype, "modulus", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerArrayBufferConverter
}), build_4$1({
name: "e",
converter: JsonBase64UrlArrayBufferConverter
})], RsaPublicKey.prototype, "publicExponent", void 0);
let EcPublicKey = class EcPublicKey {
constructor(value) {
this.value = new ArrayBuffer(0);
if (value) {
this.value = value;
}
}
toJSON() {
let bytes = new Uint8Array(this.value);
if (bytes[0] !== 0x04) {
throw new CryptoError("Wrong ECPoint. Current version supports only Uncompressed (0x04) point");
}
bytes = new Uint8Array(this.value.slice(1));
const size = bytes.length / 2;
const offset = 0;
const json = {
x: Convert.ToBase64Url(bytes.buffer.slice(offset, offset + size)),
y: Convert.ToBase64Url(bytes.buffer.slice(offset + size, offset + size + size))
};
return json;
}
fromJSON(json) {
if (!("x" in json)) {
throw new Error("x: Missing required property");
}
if (!("y" in json)) {
throw new Error("y: Missing required property");
}
const x = Convert.FromBase64Url(json.x);
const y = Convert.FromBase64Url(json.y);
const value = concat(new Uint8Array([0x04]), new Uint8Array(x), new Uint8Array(y));
this.value = new Uint8Array(value).buffer;
return this;
}
};
__decorate([build_3({
type: build_2.OctetString
})], EcPublicKey.prototype, "value", void 0);
EcPublicKey = __decorate([build_4({
type: build_1.Choice
})], EcPublicKey);
class EcPrivateKey {
constructor() {
this.version = 1;
this.privateKey = new ArrayBuffer(0);
}
fromJSON(json) {
if (!("d" in json)) {
throw new Error("d: Missing required property");
}
this.privateKey = Convert.FromBase64Url(json.d);
if ("x" in json) {
const publicKey = new EcPublicKey();
publicKey.fromJSON(json);
this.publicKey = build_6.toASN(publicKey).valueBlock.valueHex;
}
return this;
}
toJSON() {
const jwk = {};
jwk.d = Convert.ToBase64Url(this.privateKey);
if (this.publicKey) {
Object.assign(jwk, new EcPublicKey(this.publicKey).toJSON());
}
return jwk;
}
}
__decorate([build_3({
type: build_2.Integer,
converter: build_8
})], EcPrivateKey.prototype, "version", void 0);
__decorate([build_3({
type: build_2.OctetString
})], EcPrivateKey.prototype, "privateKey", void 0);
__decorate([build_3({
context: 0,
type: build_2.Any,
optional: true
})], EcPrivateKey.prototype, "parameters", void 0);
__decorate([build_3({
context: 1,
type: build_2.BitString,
optional: true
})], EcPrivateKey.prototype, "publicKey", void 0);
const AsnIntegerWithoutPaddingConverter = {
fromASN: value => {
const bytes = new Uint8Array(value.valueBlock.valueHex);
return bytes[0] === 0 ? bytes.buffer.slice(1) : bytes.buffer;
},
toASN: value => {
const bytes = new Uint8Array(value);
if (bytes[0] > 127) {
const newValue = new Uint8Array(bytes.length + 1);
newValue.set(bytes, 1);
return new asn1_26({
valueHex: newValue
});
}
return new asn1_26({
valueHex: value
});
}
};
class EcDsaSignature {
constructor() {
this.r = new ArrayBuffer(0);
this.s = new ArrayBuffer(0);
}
}
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerWithoutPaddingConverter
})], EcDsaSignature.prototype, "r", void 0);
__decorate([build_3({
type: build_2.Integer,
converter: AsnIntegerWithoutPaddingConverter
})], EcDsaSignature.prototype, "s", void 0);
class CryptoKey$1 extends CryptoKey {
constructor(algorithm, extractable, type, usages) {
super();
this.extractable = extractable;
this.type = type;
this.usages = usages;
this.algorithm = _objectSpread({}, algorithm);
}
}
function isAlgorithm(algorithm, name) {
return algorithm.name.toUpperCase() === name.toUpperCase();
}
class AesCryptoKey extends CryptoKey$1 {
constructor(algorithm, extractable, usages, raw) {
super(algorithm, extractable, "secret", usages);
this.raw = raw;
}
toJSON() {
const jwk = {
kty: "oct",
alg: this.getJwkAlgorithm(),
k: Convert.ToBase64Url(this.raw),
ext: this.extractable,
key_ops: this.usages
};
return jwk;
}
getJwkAlgorithm() {
switch (this.algorithm.name.toUpperCase()) {
case "AES-CBC":
return `A${this.algorithm.length}CBC`;
case "AES-CTR":
return `A${this.algorithm.length}CTR`;
case "AES-GCM":
return `A${this.algorithm.length}GCM`;
case "AES-ECB":
return `A${this.algorithm.length}ECB`;
default:
throw new AlgorithmError("Unsupported algorithm name");
}
}
}
class AesCrypto {
static checkLib() {
if (typeof asmCrypto === "undefined") {
throw new OperationError("Cannot implement DES mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/asmcrypto.js' script to your project");
}
}
static checkCryptoKey(key) {
if (!(key instanceof AesCryptoKey)) {
throw new TypeError("key: Is not AesCryptoKey");
}
}
static async generateKey(algorithm, extractable, usages) {
this.checkLib();
const raw = nativeCrypto.getRandomValues(new Uint8Array(algorithm.length / 8));
return new AesCryptoKey(algorithm, extractable, usages, raw);
}
static async encrypt(algorithm, key, data) {
return this.cipher(algorithm, key, data, true);
}
static async decrypt(algorithm, key, data) {
return this.cipher(algorithm, key, data, false);
}
static async exportKey(format, key) {
this.checkLib();
switch (format) {
case "jwk":
return key.toJSON();
case "raw":
return key.raw.buffer;
default:
throw new OperationError("format: Must be 'jwk' or 'raw'");
}
}
static async importKey(format, keyData, algorithm, extractable, keyUsages) {
this.checkLib();
let raw;
if (isJWK(keyData)) {
raw = Convert.FromBase64Url(keyData.k);
} else {
raw = BufferSourceConverter.toArrayBuffer(keyData);
}
switch (raw.byteLength << 3) {
case 128:
case 192:
case 256:
break;
default:
throw new OperationError("keyData: Is wrong key length");
}
const key = new AesCryptoKey({
name: algorithm.name,
length: raw.byteLength << 3
}, extractable, keyUsages, new Uint8Array(raw));
return key;
}
static async cipher(algorithm, key, data, encrypt) {
this.checkLib();
const action = encrypt ? "encrypt" : "decrypt";
let res;
if (isAlgorithm(algorithm, AesCrypto.AesCBC)) {
const iv = BufferSourceConverter.toArrayBuffer(algorithm.iv);
res = asmCrypto.AES_CBC[action](data, key.raw, undefined, iv);
} else if (isAlgorithm(algorithm, AesCrypto.AesGCM)) {
const iv = BufferSourceConverter.toArrayBuffer(algorithm.iv);
let additionalData;
if (algorithm.additionalData) {
additionalData = BufferSourceConverter.toArrayBuffer(algorithm.additionalData);
}
const tagLength = (algorithm.tagLength || 128) / 8;
res = asmCrypto.AES_GCM[action](data, key.raw, iv, additionalData, tagLength);
} else if (isAlgorithm(algorithm, AesCrypto.AesECB)) {
res = asmCrypto.AES_ECB[action](data, key.raw, true);
} else {
throw new OperationError(`algorithm: Is not recognized`);
}
return res.buffer;
}
}
AesCrypto.AesCBC = "AES-CBC";
AesCrypto.AesECB = "AES-ECB";
AesCrypto.AesGCM = "AES-GCM";
class AesCbcProvider$1 extends AesCbcProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return AesCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onEncrypt(algorithm, key, data) {
return AesCrypto.encrypt(algorithm, key, data);
}
async onDecrypt(algorithm, key, data) {
return AesCrypto.decrypt(algorithm, key, data);
}
async onExportKey(format, key) {
return AesCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
AesCrypto.checkCryptoKey(key);
}
}
class AesEcbProvider$1 extends AesEcbProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return AesCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onEncrypt(algorithm, key, data) {
return AesCrypto.encrypt(algorithm, key, data);
}
async onDecrypt(algorithm, key, data) {
return AesCrypto.decrypt(algorithm, key, data);
}
async onExportKey(format, key) {
return AesCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
AesCrypto.checkCryptoKey(key);
}
}
class AesGcmProvider$1 extends AesGcmProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return AesCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onEncrypt(algorithm, key, data) {
return AesCrypto.encrypt(algorithm, key, data);
}
async onDecrypt(algorithm, key, data) {
return AesCrypto.decrypt(algorithm, key, data);
}
async onExportKey(format, key) {
return AesCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return AesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
AesCrypto.checkCryptoKey(key);
}
}
class AesCtrProvider$1 extends AesCtrProvider {
async onEncrypt(algorithm, key, data) {
throw new Error("Method not implemented.");
}
async onDecrypt(algorithm, key, data) {
throw new Error("Method not implemented.");
}
async onGenerateKey(algorithm, extractable, keyUsages) {
throw new Error("Method not implemented.");
}
async onExportKey(format, key) {
throw new Error("Method not implemented.");
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
throw new Error("Method not implemented.");
}
}
class AesKwProvider$1 extends AesKwProvider {
async onEncrypt(algorithm, key, data) {
throw new Error("Method not implemented.");
}
async onDecrypt(algorithm, key, data) {
throw new Error("Method not implemented.");
}
async onGenerateKey(algorithm, extractable, keyUsages) {
throw new Error("Method not implemented.");
}
async onExportKey(format, key) {
throw new Error("Method not implemented.");
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
throw new Error("Method not implemented.");
}
}
class RsaCryptoKey extends CryptoKey$1 {
constructor(algorithm, extractable, type, usages, data) {
super(algorithm, extractable, type, usages);
this.data = data;
}
}
class RsaCrypto {
static checkLib() {
if (typeof asmCrypto === "undefined") {
throw new OperationError("Cannot implement DES mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/asmcrypto.js' script to your project");
}
}
static checkCryptoKey(key) {
if (!(key instanceof RsaCryptoKey)) {
throw new TypeError("key: Is not RsaCryptoKey");
}
}
static async generateKey(algorithm, extractable, keyUsages) {
this.checkLib();
const pubExp = algorithm.publicExponent[0] === 3 ? 3 : 65537;
const rsaKey = asmCrypto.RSA.generateKey(algorithm.modulusLength, pubExp);
const hashAlgorithm = algorithm.hash.name.toUpperCase();
const privateKey = new RsaCryptoKey(_objectSpread({}, algorithm, {
hash: {
name: hashAlgorithm
}
}), extractable, "private", keyUsages.filter(usage => ~this.privateUsages.indexOf(usage)), rsaKey);
const publicKey = new RsaCryptoKey(_objectSpread({}, algorithm, {
hash: {
name: hashAlgorithm
}
}), true, "public", keyUsages.filter(usage => ~this.publicUsages.indexOf(usage)), rsaKey);
return {
privateKey,
publicKey
};
}
static async exportKey(format, key) {
this.checkLib();
switch (format) {
case "pkcs8":
return this.exportPkcs8Key(key);
case "spki":
return this.exportSpkiKey(key);
case "jwk":
return this.exportJwkKey(key);
default:
throw new OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'");
}
}
static async importKey(format, keyData, algorithm, extractable, keyUsages) {
this.checkLib();
let asmKey;
switch (format) {
case "pkcs8":
asmKey = this.importPkcs8Key(keyData);
break;
case "spki":
asmKey = this.importSpkiKey(keyData);
break;
case "jwk":
asmKey = this.importJwkKey(keyData);
break;
default:
throw new OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'");
}
const key = new RsaCryptoKey(_objectSpread({
publicExponent: asmKey[1][1] === 1 ? asmKey[1].slice(1) : asmKey[1].slice(3),
modulusLength: asmKey[0].byteLength << 3
}, algorithm), extractable, asmKey.length === 2 ? "public" : "private", keyUsages, asmKey);
return key;
}
static exportPkcs8Key(key) {
const keyInfo = new PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.privateKeyAlgorithm.parameters = null;
keyInfo.privateKey = build_6.serialize(this.exportAsmKey(key.data));
return build_6.serialize(keyInfo);
}
static importPkcs8Key(data) {
const keyInfo = build_5.parse(data, PrivateKeyInfo);
const privateKey = build_5.parse(keyInfo.privateKey, RsaPrivateKey);
return this.importAsmKey(privateKey);
}
static importSpkiKey(data) {
const keyInfo = build_5.parse(data, PublicKeyInfo);
const publicKey = build_5.parse(keyInfo.publicKey, RsaPublicKey);
return this.importAsmKey(publicKey);
}
static exportSpkiKey(key) {
const publicKey = new RsaPublicKey();
publicKey.modulus = key.data[0].buffer;
publicKey.publicExponent = key.data[1][1] === 1 ? key.data[1].buffer.slice(1) : key.data[1].buffer.slice(3);
const keyInfo = new PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.publicKeyAlgorithm.parameters = null;
keyInfo.publicKey = build_6.serialize(publicKey);
return build_6.serialize(keyInfo);
}
static importJwkKey(data) {
let key;
if (data.d) {
key = build_3$1.fromJSON(data, {
targetSchema: RsaPrivateKey
});
} else {
key = build_3$1.fromJSON(data, {
targetSchema: RsaPublicKey
});
}
return this.importAsmKey(key);
}
static exportJwkKey(key) {
const asnKey = this.exportAsmKey(key.data);
const jwk = build_2$1.toJSON(asnKey);
jwk.ext = true;
jwk.key_ops = key.usages;
jwk.kty = "RSA";
jwk.alg = this.getJwkAlgorithm(key.algorithm);
return jwk;
}
static getJwkAlgorithm(algorithm) {
switch (algorithm.name.toUpperCase()) {
case "RSA-OAEP":
const mdSize = /(\d+)$/.exec(algorithm.hash.name)[1];
return `RSA-OAEP${mdSize !== "1" ? `-${mdSize}` : ""}`;
case "RSASSA-PKCS1-V1_5":
return `RS${/(\d+)$/.exec(algorithm.hash.name)[1]}`;
case "RSA-PSS":
return `PS${/(\d+)$/.exec(algorithm.hash.name)[1]}`;
default:
throw new OperationError("algorithm: Is not recognized");
}
}
static exportAsmKey(asmKey) {
let key;
if (asmKey.length > 2) {
const privateKey = new RsaPrivateKey();
privateKey.privateExponent = asmKey[2].buffer;
privateKey.prime1 = asmKey[3].buffer;
privateKey.prime2 = asmKey[4].buffer;
privateKey.exponent1 = asmKey[5].buffer;
privateKey.exponent2 = asmKey[6].buffer;
privateKey.coefficient = asmKey[7].buffer;
key = privateKey;
} else {
key = new RsaPublicKey();
}
key.modulus = asmKey[0].buffer;
key.publicExponent = asmKey[1][1] === 1 ? asmKey[1].buffer.slice(1) : asmKey[1].buffer.slice(3);
return key;
}
static importAsmKey(key) {
const expPadding = new Uint8Array(4 - key.publicExponent.byteLength);
const asmKey = [new Uint8Array(key.modulus), concat(expPadding, new Uint8Array(key.publicExponent))];
if (key instanceof RsaPrivateKey) {
asmKey.push(new Uint8Array(key.privateExponent));
asmKey.push(new Uint8Array(key.prime1));
asmKey.push(new Uint8Array(key.prime2));
asmKey.push(new Uint8Array(key.exponent1));
asmKey.push(new Uint8Array(key.exponent2));
asmKey.push(new Uint8Array(key.coefficient));
}
return asmKey;
}
}
RsaCrypto.RsaSsa = "RSASSA-PKCS1-v1_5";
RsaCrypto.RsaPss = "RSA-PSS";
RsaCrypto.RsaOaep = "RSA-OAEP";
RsaCrypto.privateUsages = ["sign", "decrypt", "unwrapKey"];
RsaCrypto.publicUsages = ["verify", "encrypt", "wrapKey"];
class RsaOaepProvider$1 extends RsaOaepProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return RsaCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return RsaCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return RsaCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onEncrypt(algorithm, key, data) {
RsaCrypto.checkLib();
return this.cipher(algorithm, key, data, true);
}
async onDecrypt(algorithm, key, data) {
RsaCrypto.checkLib();
return this.cipher(algorithm, key, data, false);
}
cipher(algorithm, key, data, encrypt) {
const fn = this.getOperation(key.algorithm, encrypt);
let label;
if (algorithm.label) {
label = BufferSourceConverter.toArrayBuffer(algorithm.label);
}
return fn(data, key.data, label).slice(0).buffer;
}
getOperation(keyAlgorithm, encrypt) {
const action = encrypt ? "encrypt" : "decrypt";
switch (keyAlgorithm.hash.name) {
case "SHA-1":
return asmCrypto.RSA_OAEP_SHA1[action];
case "SHA-256":
return asmCrypto.RSA_OAEP_SHA256[action];
case "SHA-512":
return asmCrypto.RSA_OAEP_SHA512[action];
default:
throw new AlgorithmError("keyAlgorithm.hash: Is not recognized");
}
}
}
class RsaPssProvider$1 extends RsaPssProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return RsaCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return RsaCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return RsaCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onSign(algorithm, key, data) {
RsaCrypto.checkLib();
const fn = this.getOperation(key.algorithm, true);
return fn(data, key.data, algorithm.saltLength).buffer;
}
async onVerify(algorithm, key, signature, data) {
RsaCrypto.checkLib();
const fn = this.getOperation(key.algorithm, false);
return fn(signature, data, key.data, algorithm.saltLength);
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
RsaCrypto.checkCryptoKey(key);
}
getOperation(keyAlgorithm, sign) {
const action = sign ? "sign" : "verify";
switch (keyAlgorithm.hash.name) {
case "SHA-1":
return asmCrypto.RSA_PSS_SHA1[action];
case "SHA-256":
return asmCrypto.RSA_PSS_SHA256[action];
case "SHA-512":
return asmCrypto.RSA_PSS_SHA512[action];
default:
throw new AlgorithmError("keyAlgorithm.hash: Is not recognized");
}
}
}
class RsaSsaProvider$1 extends RsaSsaProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return RsaCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return RsaCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return RsaCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onSign(algorithm, key, data) {
RsaCrypto.checkLib();
const fn = this.getOperation(key.algorithm, true);
return fn(data, key.data).buffer;
}
async onVerify(algorithm, key, signature, data) {
RsaCrypto.checkLib();
const fn = this.getOperation(key.algorithm, false);
return fn(signature, data, key.data);
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
RsaCrypto.checkCryptoKey(key);
}
getOperation(keyAlgorithm, sign) {
const action = sign ? "sign" : "verify";
switch (keyAlgorithm.hash.name) {
case "SHA-1":
return asmCrypto.RSA_PKCS1_v1_5_SHA1[action];
case "SHA-256":
return asmCrypto.RSA_PKCS1_v1_5_SHA256[action];
case "SHA-512":
return asmCrypto.RSA_PKCS1_v1_5_SHA512[action];
default:
throw new AlgorithmError("keyAlgorithm.hash: Is not recognized");
}
}
}
const namedOIDs = {
"1.2.840.10045.3.1.7": "P-256",
"P-256": "1.2.840.10045.3.1.7",
"1.3.132.0.34": "P-384",
"P-384": "1.3.132.0.34",
"1.3.132.0.35": "P-521",
"P-521": "1.3.132.0.35",
"1.3.132.0.10": "K-256",
"K-256": "1.3.132.0.10"
};
function getOidByNamedCurve(namedCurve) {
const oid = namedOIDs[namedCurve];
if (!oid) {
throw new OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`);
}
return oid;
}
class EcCryptoKey extends CryptoKey$1 {
constructor(algorithm, extractable, type, usages, data) {
super(algorithm, extractable, type, usages);
this.data = data;
}
}
class EcCrypto {
static checkLib() {
if (typeof elliptic === "undefined") {
throw new OperationError("Cannot implement DES mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/elliptic.js' script to your project");
}
}
static async generateKey(algorithm, extractable, keyUsages) {
this.checkLib();
const key = this.initEcKey(algorithm.namedCurve);
const ecKey = key.genKeyPair();
ecKey.getPublic();
const prvKey = new EcCryptoKey(_objectSpread({}, algorithm), extractable, "private", keyUsages.filter(usage => ~this.privateUsages.indexOf(usage)), ecKey);
const pubKey = new EcCryptoKey(_objectSpread({}, algorithm), true, "public", keyUsages.filter(usage => ~this.publicUsages.indexOf(usage)), ecKey);
return {
privateKey: prvKey,
publicKey: pubKey
};
}
static checkCryptoKey(key) {
if (!(key instanceof EcCryptoKey)) {
throw new TypeError("key: Is not EcCryptoKey");
}
}
static concat(...buf) {
const res = new Uint8Array(buf.map(item => item.length).reduce((prev, cur) => prev + cur));
let offset = 0;
buf.forEach((item, index) => {
for (let i = 0; i < item.length; i++) {
res[offset + i] = item[i];
}
offset += item.length;
});
return res;
}
static async exportKey(format, key) {
this.checkLib();
switch (format) {
case "pkcs8":
return this.exportPkcs8Key(key);
case "spki":
return this.exportSpkiKey(key);
case "jwk":
return this.exportJwkKey(key);
case "raw":
return new Uint8Array(key.data.getPublic("der")).buffer;
default:
throw new OperationError("format: Must be 'jwk', 'raw, 'pkcs8' or 'spki'");
}
}
static async importKey(format, keyData, algorithm, extractable, keyUsages) {
this.checkLib();
let ecKey;
switch (format) {
case "pkcs8":
ecKey = this.importPkcs8Key(keyData, algorithm.namedCurve);
break;
case "spki":
ecKey = this.importSpkiKey(keyData, algorithm.namedCurve);
break;
case "raw":
ecKey = this.importEcKey(new EcPublicKey(keyData), algorithm.namedCurve);
break;
case "jwk":
ecKey = this.importJwkKey(keyData);
break;
default:
throw new OperationError("format: Must be 'jwk', 'raw', 'pkcs8' or 'spki'");
}
const key = new EcCryptoKey(_objectSpread({}, algorithm), extractable, ecKey.priv ? "private" : "public", keyUsages, ecKey);
return key;
}
static getNamedCurve(wcNamedCurve) {
const crv = wcNamedCurve.toUpperCase();
let res = "";
if (["P-256", "P-384", "P-521"].indexOf(crv) > -1) {
res = crv.replace("-", "").toLowerCase();
} else if (crv === "K-256") {
res = "secp256k1";
} else {
throw new OperationError(`Unsupported named curve '${wcNamedCurve}'`);
}
return res;
}
static initEcKey(namedCurve) {
return elliptic.ec(this.getNamedCurve(namedCurve));
}
static exportPkcs8Key(key) {
const keyInfo = new PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = this.ASN_ALGORITHM;
keyInfo.privateKeyAlgorithm.parameters = build_6.serialize(new ObjectIdentifier(getOidByNamedCurve(key.algorithm.namedCurve)));
keyInfo.privateKey = build_6.serialize(this.exportEcKey(key));
return build_6.serialize(keyInfo);
}
static importPkcs8Key(data, namedCurve) {
const keyInfo = build_5.parse(data, PrivateKeyInfo);
const privateKey = build_5.parse(keyInfo.privateKey, EcPrivateKey);
return this.importEcKey(privateKey, namedCurve);
}
static importSpkiKey(data, namedCurve) {
const keyInfo = build_5.parse(data, PublicKeyInfo);
const publicKey = new EcPublicKey(keyInfo.publicKey);
return this.importEcKey(publicKey, namedCurve);
}
static exportSpkiKey(key) {
const publicKey = new EcPublicKey(new Uint8Array(key.data.getPublic("der")).buffer);
const keyInfo = new PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = this.ASN_ALGORITHM;
keyInfo.publicKeyAlgorithm.parameters = build_6.serialize(new ObjectIdentifier(getOidByNamedCurve(key.algorithm.namedCurve)));
keyInfo.publicKey = publicKey.value;
return build_6.serialize(keyInfo);
}
static importJwkKey(data) {
let key;
if (data.d) {
key = build_3$1.fromJSON(data, {
targetSchema: EcPrivateKey
});
} else {
key = build_3$1.fromJSON(data, {
targetSchema: EcPublicKey
});
}
return this.importEcKey(key, data.crv);
}
static exportJwkKey(key) {
const asnKey = this.exportEcKey(key);
const jwk = build_2$1.toJSON(asnKey);
jwk.ext = true;
jwk.key_ops = key.usages;
jwk.crv = key.algorithm.namedCurve;
jwk.kty = "EC";
return jwk;
}
static exportEcKey(ecKey) {
if (ecKey.type === "private") {
const privateKey = new EcPrivateKey();
const point = new Uint8Array(ecKey.data.getPrivate("der").toArray());
const pointPad = new Uint8Array(this.getPointSize(ecKey.algorithm.namedCurve) - point.length);
privateKey.privateKey = concat(pointPad, point);
privateKey.publicKey = new Uint8Array(ecKey.data.getPublic("der"));
return privateKey;
} else if (ecKey.data.pub) {
return new EcPublicKey(new Uint8Array(ecKey.data.getPublic("der")).buffer);
} else {
throw new Error("Cannot get private or public key");
}
}
static importEcKey(key, namedCurve) {
const ecKey = this.initEcKey(namedCurve);
if (key instanceof EcPublicKey) {
return ecKey.keyFromPublic(new Uint8Array(key.value));
}
return ecKey.keyFromPrivate(new Uint8Array(key.privateKey));
}
static getPointSize(namedCurve) {
switch (namedCurve) {
case "P-256":
case "K-256":
return 32;
case "P-384":
return 48;
case "P-521":
return 66;
}
throw new Error("namedCurve: Is not recognized");
}
}
EcCrypto.privateUsages = ["sign", "deriveKey", "deriveBits"];
EcCrypto.publicUsages = ["verify"];
EcCrypto.ASN_ALGORITHM = "1.2.840.10045.2.1";
class EcdhProvider$1 extends EcdhProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return EcCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return EcCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return EcCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onDeriveBits(algorithm, baseKey, length) {
EcCrypto.checkLib();
const shared = baseKey.data.derive(algorithm.public.data.getPublic());
let array = new Uint8Array(shared.toArray());
let len = array.length;
len = len > 32 ? len > 48 ? 66 : 48 : 32;
if (array.length < len) {
array = EcCrypto.concat(new Uint8Array(len - array.length), array);
}
const buf = array.slice(0, length / 8).buffer;
return buf;
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
EcCrypto.checkCryptoKey(key);
}
}
function b2a(buffer) {
const buf = new Uint8Array(buffer);
const res = [];
for (let i = 0; i < buf.length; i++) {
res.push(buf[i]);
}
return res;
}
function hex2buffer(hexString, padded) {
if (hexString.length % 2) {
hexString = "0" + hexString;
}
let res = new Uint8Array(hexString.length / 2);
for (let i = 0; i < hexString.length; i++) {
const c = hexString.slice(i, ++i + 1);
res[(i - 1) / 2] = parseInt(c, 16);
}
if (padded) {
let len = res.length;
len = len > 32 ? len > 48 ? 66 : 48 : 32;
if (res.length < len) {
res = EcCrypto.concat(new Uint8Array(len - res.length), res);
}
}
return res;
}
function buffer2hex(buffer, padded) {
let res = "";
for (let i = 0; i < buffer.length; i++) {
const char = buffer[i].toString(16);
res += char.length % 2 ? "0" + char : char;
}
if (padded) {
let len = buffer.length;
len = len > 32 ? len > 48 ? 66 : 48 : 32;
if (res.length / 2 < len) {
res = new Array(len * 2 - res.length + 1).join("0") + res;
}
}
return res;
}
class EcdsaProvider$1 extends EcdsaProvider {
async onGenerateKey(algorithm, extractable, keyUsages) {
return EcCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return EcCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return EcCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onSign(algorithm, key, data) {
EcCrypto.checkLib();
const crypto = new Crypto$1();
let array;
const hash = await crypto.subtle.digest(algorithm.hash, data);
array = b2a(hash);
const signature = await key.data.sign(array);
const hexSignature = buffer2hex(signature.r.toArray(), true) + buffer2hex(signature.s.toArray(), true);
return hex2buffer(hexSignature).buffer;
}
async onVerify(algorithm, key, signature, data) {
EcCrypto.checkLib();
const crypto = new Crypto$1();
const sig = {
r: new Uint8Array(signature.slice(0, signature.byteLength / 2)),
s: new Uint8Array(signature.slice(signature.byteLength / 2))
};
const hashedData = await crypto.subtle.digest(algorithm.hash, data);
const array = b2a(hashedData);
return key.data.verify(array, sig);
}
async checkCryptoKey(key, keyUsage) {
super.checkCryptoKey(key, keyUsage);
EcCrypto.checkCryptoKey(key);
}
}
class ShaCrypto {
static checkLib() {
if (typeof asmCrypto === "undefined") {
throw new OperationError("Cannot implement DES mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/asmcrypto.js' script to your project");
}
}
static async digest(algorithm, data) {
this.checkLib();
const mech = asmCrypto[algorithm.name.replace("-", "")];
return mech.bytes(data).buffer;
}
}
class Sha1Provider extends ProviderCrypto {
constructor() {
super(...arguments);
this.name = "SHA-1";
this.usages = [];
}
async onDigest(algorithm, data) {
return ShaCrypto.digest(algorithm, data);
}
}
class Sha256Provider extends Sha1Provider {
constructor() {
super(...arguments);
this.name = "SHA-256";
}
}
class Sha512Provider extends Sha1Provider {
constructor() {
super(...arguments);
this.name = "SHA-512";
}
}
class PbkdfCryptoKey extends CryptoKey$1 {
constructor(algorithm, extractable, usages, raw) {
super(algorithm, extractable, "secret", usages);
this.raw = raw;
}
}
class Pbkdf2Provider$1 extends Pbkdf2Provider {
checkLib() {
if (typeof asmCrypto === "undefined") {
throw new OperationError("Cannot implement DES mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/asmcrypto.js' script to your project");
}
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
this.checkLib();
return new PbkdfCryptoKey(algorithm, extractable, keyUsages, BufferSourceConverter.toUint8Array(keyData));
}
async onDeriveBits(algorithm, baseKey, length) {
this.checkLib();
let result;
const salt = BufferSourceConverter.toUint8Array(algorithm.salt);
const password = baseKey.raw;
switch (algorithm.hash.name.toUpperCase()) {
case "SHA-1":
result = asmCrypto.PBKDF2_HMAC_SHA1.bytes(password, salt, algorithm.iterations, length >> 3);
break;
case "SHA-256":
result = asmCrypto.PBKDF2_HMAC_SHA256.bytes(password, salt, algorithm.iterations, length >> 3);
break;
default:
throw new OperationError(`algorithm.hash: '${algorithm.hash.name}' hash algorithm is not supported`);
}
return result.buffer;
}
}
class DesCryptoKey extends CryptoKey$1 {
constructor(algorithm, extractable, usages, raw) {
super(algorithm, extractable, "secret", usages);
this.raw = raw;
}
toJSON() {
const jwk = {
kty: "oct",
alg: this.getJwkAlgorithm(),
k: Convert.ToBase64Url(this.raw),
ext: this.extractable,
key_ops: this.usages
};
return jwk;
}
getJwkAlgorithm() {
switch (this.algorithm.name.toUpperCase()) {
case "DES-CBC":
return `DES-CBC`;
case "DES-EDE3-CBC":
return `3DES-CBC`;
default:
throw new AlgorithmError("Unsupported algorithm name");
}
}
}
class DesCrypto {
static checkLib() {
if (typeof des === "undefined") {
throw new OperationError("Cannot implement DES mechanism. Add 'https://peculiarventures.github.io/pv-webcrypto-tests/src/des.js' script to your project");
}
}
static async generateKey(algorithm, extractable, keyUsages) {
this.checkLib();
const raw = nativeCrypto.getRandomValues(new Uint8Array(algorithm.length / 8));
return new DesCryptoKey(algorithm, extractable, keyUsages, raw);
}
static async exportKey(format, key) {
this.checkLib();
switch (format) {
case "jwk":
return key.toJSON();
case "raw":
return key.raw.buffer;
default:
throw new OperationError("format: Must be 'jwk' or 'raw'");
}
}
static async importKey(format, keyData, algorithm, extractable, keyUsages) {
this.checkLib();
let raw;
if (isJWK(keyData)) {
raw = Convert.FromBase64Url(keyData.k);
} else {
raw = BufferSourceConverter.toArrayBuffer(keyData);
}
if (algorithm.name === "DES-CBC" && raw.byteLength !== 8 || algorithm.name === "DES-EDE3-CBC" && raw.byteLength !== 24) {
throw new OperationError("keyData: Is wrong key length");
}
const key = new DesCryptoKey({
name: algorithm.name,
length: raw.byteLength << 3
}, extractable, keyUsages, new Uint8Array(raw));
return key;
}
static async encrypt(algorithm, key, data) {
return this.cipher(algorithm, key, data, true);
}
static async decrypt(algorithm, key, data) {
return this.cipher(algorithm, key, data, false);
}
static async cipher(algorithm, key, data, encrypt) {
this.checkLib();
const type = encrypt ? "encrypt" : "decrypt";
let DesCipher;
const iv = BufferSourceConverter.toUint8Array(algorithm.iv);
switch (algorithm.name.toUpperCase()) {
case "DES-CBC":
DesCipher = des.CBC.instantiate(des.DES).create({
key: key.raw,
type,
iv
});
break;
case "DES-EDE3-CBC":
DesCipher = des.CBC.instantiate(des.EDE).create({
key: key.raw,
type,
iv
});
break;
default:
throw new OperationError("algorithm: Is not recognized");
}
const enc = DesCipher.update(new Uint8Array(data)).concat(DesCipher.final());
return new Uint8Array(enc).buffer;
}
}
class DesCbcProvider extends DesProvider {
constructor() {
super(...arguments);
this.keySizeBits = 64;
this.ivSize = 8;
this.name = "DES-CBC";
}
async onGenerateKey(algorithm, extractable, keyUsages) {
return DesCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return DesCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return DesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onEncrypt(algorithm, key, data) {
return DesCrypto.encrypt(algorithm, key, data);
}
async onDecrypt(algorithm, key, data) {
return DesCrypto.decrypt(algorithm, key, data);
}
}
class DesEde3CbcProvider extends DesProvider {
constructor() {
super(...arguments);
this.keySizeBits = 192;
this.ivSize = 8;
this.name = "DES-EDE3-CBC";
}
async onGenerateKey(algorithm, extractable, keyUsages) {
return DesCrypto.generateKey(algorithm, extractable, keyUsages);
}
async onExportKey(format, key) {
return DesCrypto.exportKey(format, key);
}
async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
return DesCrypto.importKey(format, keyData, algorithm, extractable, keyUsages);
}
async onEncrypt(algorithm, key, data) {
return DesCrypto.encrypt(algorithm, key, data);
}
async onDecrypt(algorithm, key, data) {
return DesCrypto.decrypt(algorithm, key, data);
}
}
class SubtleCrypto$1 extends SubtleCrypto {
constructor() {
super();
this.browserInfo = BrowserInfo();
this.providers.set(new AesCbcProvider$1());
this.providers.set(new AesCtrProvider$1());
this.providers.set(new AesEcbProvider$1());
this.providers.set(new AesGcmProvider$1());
this.providers.set(new AesKwProvider$1());
this.providers.set(new DesCbcProvider());
this.providers.set(new DesEde3CbcProvider());
this.providers.set(new RsaSsaProvider$1());
this.providers.set(new RsaPssProvider$1());
this.providers.set(new RsaOaepProvider$1());
this.providers.set(new EcdsaProvider$1());
this.providers.set(new EcdhProvider$1());
this.providers.set(new Sha1Provider());
this.providers.set(new Sha256Provider());
this.providers.set(new Sha512Provider());
this.providers.set(new Pbkdf2Provider$1());
}
static isAnotherKey(key) {
if (typeof key === "object" && typeof key.type === "string" && typeof key.extractable === "boolean" && typeof key.algorithm === "object") {
return !(key instanceof CryptoKey$1);
}
return false;
}
async digest(...args) {
return this.wrapNative("digest", ...args);
}
async importKey(...args) {
this.fixFirefoxEcImportPkcs8(args);
return this.wrapNative("importKey", ...args);
}
async exportKey(...args) {
return (await this.fixFirefoxEcExportPkcs8(args)) || (await this.wrapNative("exportKey", ...args));
}
async generateKey(...args) {
return this.wrapNative("generateKey", ...args);
}
async sign(...args) {
return this.wrapNative("sign", ...args);
}
async verify(...args) {
return this.wrapNative("verify", ...args);
}
async encrypt(...args) {
return this.wrapNative("encrypt", ...args);
}
async decrypt(...args) {
return this.wrapNative("decrypt", ...args);
}
async wrapKey(...args) {
return this.wrapNative("wrapKey", ...args);
}
async unwrapKey(...args) {
return this.wrapNative("unwrapKey", ...args);
}
async deriveBits(...args) {
return this.wrapNative("deriveBits", ...args);
}
async deriveKey(...args) {
return this.wrapNative("deriveKey", ...args);
}
async wrapNative(method, ...args) {
if (~["generateKey", "unwrapKey", "deriveKey", "importKey"].indexOf(method)) {
this.fixAlgorithmName(args);
}
try {
if (method !== "digest" || !args.some(a => a instanceof CryptoKey$1)) {
Debug.info(`Call native '${method}' method`, args);
const res = await nativeSubtle[method].apply(nativeSubtle, args);
return res;
}
} catch (e) {
Debug.warn(`Error on native '${method}' calling. ${e.message}`, e);
}
if (method === "wrapKey") {
try {
Debug.info(`Trying to wrap key by using native functions`, args);
const data = await this.exportKey(args[0], args[1]);
const keyData = args[0] === "jwk" ? Convert.FromUtf8String(JSON.stringify(data)) : data;
const res = await this.encrypt(args[3], args[2], keyData);
return res;
} catch (e) {
Debug.warn(`Cannot wrap key by native functions. ${e.message}`, e);
}
}
if (method === "unwrapKey") {
try {
Debug.info(`Trying to unwrap key by using native functions`, args);
const data = await this.decrypt(args[3], args[2], args[1]);
const keyData = args[0] === "jwk" ? JSON.parse(Convert.ToUtf8String(data)) : data;
const res = await this.importKey(args[0], keyData, args[4], args[5], args[6]);
return res;
} catch (e) {
Debug.warn(`Cannot unwrap key by native functions. ${e.message}`, e);
}
}
if (method === "deriveKey") {
try {
Debug.info(`Trying to derive key by using native functions`, args);
const data = await this.deriveBits(args[0], args[1], args[2].length);
const res = await this.importKey("raw", data, args[2], args[3], args[4]);
return res;
} catch (e) {
Debug.warn(`Cannot derive key by native functions. ${e.message}`, e);
}
}
if (method === "deriveBits" || method === "deriveKey") {
for (const arg of args) {
if (typeof arg === "object" && arg.public && SubtleCrypto$1.isAnotherKey(arg.public)) {
arg.public = await this.castKey(arg.public);
}
}
}
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (SubtleCrypto$1.isAnotherKey(arg)) {
args[i] = await this.castKey(arg);
}
}
return super[method].apply(this, args);
}
async castKey(key) {
Debug.info("Cast native CryptoKey to linter key.", key);
if (!key.extractable) {
throw new Error("Cannot cast unextractable crypto key");
}
const provider = this.getProvider(key.algorithm.name);
const jwk = await this.exportKey("jwk", key);
return provider.importKey("jwk", jwk, key.algorithm, true, key.usages);
}
fixAlgorithmName(args) {
if (this.browserInfo.name === Browser.Edge) {
for (let i = 0; i < args.length; i++) {
const arg = args[0];
if (typeof arg === "string") {
for (const algorithm of this.providers.algorithms) {
if (algorithm.toLowerCase() === arg.toLowerCase()) {
args[i] = algorithm;
break;
}
}
} else if (typeof arg === "object" && typeof arg.name === "string") {
for (const algorithm of this.providers.algorithms) {
if (algorithm.toLowerCase() === arg.name.toLowerCase()) {
arg.name = algorithm;
}
if (typeof arg.hash === "string" && algorithm.toLowerCase() === arg.hash.toLowerCase() || typeof arg.hash === "object" && typeof arg.hash.name === "string" && algorithm.toLowerCase() === arg.hash.name.toLowerCase()) {
arg.hash = {
name: algorithm
};
}
}
}
}
}
}
fixFirefoxEcImportPkcs8(args) {
const preparedAlgorithm = this.prepareAlgorithm(args[2]);
const algName = preparedAlgorithm.name.toUpperCase();
if (this.browserInfo.name === Browser.Firefox && args[0] === "pkcs8" && ~["ECDSA", "ECDH"].indexOf(algName) && ~["P-256", "P-384", "P-521"].indexOf(preparedAlgorithm.namedCurve)) {
if (!BufferSourceConverter.isBufferSource(args[1])) {
throw new TypeError("data: Is not ArrayBuffer or ArrayBufferView");
}
const preparedData = BufferSourceConverter.toArrayBuffer(args[1]);
const keyInfo = build_5.parse(preparedData, PrivateKeyInfo);
const privateKey = build_5.parse(keyInfo.privateKey, EcPrivateKey);
const jwk = build_2$1.toJSON(privateKey);
jwk.ext = true;
jwk.key_ops = args[4];
jwk.crv = preparedAlgorithm.namedCurve;
jwk.kty = "EC";
args[0] = "jwk";
args[1] = jwk;
}
}
async fixFirefoxEcExportPkcs8(args) {
try {
if (this.browserInfo.name === Browser.Firefox && args[0] === "pkcs8" && ~["ECDSA", "ECDH"].indexOf(args[1].algorithm.name) && ~["P-256", "P-384", "P-521"].indexOf(args[1].algorithm.namedCurve)) {
const jwk = await this.exportKey("jwk", args[1]);
const ecKey = build_3$1.fromJSON(jwk, {
targetSchema: EcPrivateKey
});
const keyInfo = new PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = EcCrypto.ASN_ALGORITHM;
keyInfo.privateKeyAlgorithm.parameters = build_6.serialize(new ObjectIdentifier(getOidByNamedCurve(args[1].algorithm.namedCurve)));
keyInfo.privateKey = build_6.serialize(ecKey);
return build_6.serialize(keyInfo);
}
} catch (err) {
Debug.error(err);
return null;
}
}
}
SubtleCrypto$1.methods = ["digest", "importKey", "exportKey", "sign", "verify", "generateKey", "encrypt", "decrypt", "deriveBits", "deriveKey", "wrapKey", "unwrapKey"];
class Crypto$1 extends Crypto {
constructor() {
super(...arguments);
this.subtle = new SubtleCrypto$1();
}
getRandomValues(array) {
return nativeCrypto.getRandomValues(array);
}
}
if (!Math.imul) {
Math.imul = function imul(a, b) {
const ah = a >>> 16 & 0xffff;
const al = a & 0xffff;
const bh = b >>> 16 & 0xffff;
const bl = b & 0xffff;
return al * bl + (ah * bl + al * bh << 16 >>> 0) | 0;
};
}
exports.crypto = new Crypto$1(); // section modified by isomorphic-webcrypto build
return exports;
}({}));
module.exports = liner; // section modified by isomorphic-webcrypto build
Выполнить команду
Для локальной разработки. Не используйте в интернете!