crypto-pro-js/src/apiSync.js

528 lines
17 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var cryptoCommon = require('./common'),
cryptoConstants = require('./constants'),
_certListCache;
function Certificate(item) {
this._cert = item._cert;
this.thumbprint = item.thumbprint;
this.subjectName = item.subjectName;
this.issuerName = item.issuerName;
this.validFrom = item.validFrom;
this.validTo = item.validTo;
}
/**
* Проверяет, валиден ли сертификат
* */
Certificate.prototype.isValid = function isValid() {
var cert = this._cert;
return new Promise(function (resolve, reject) {
var result;
try {
result = cert.IsValid();
result = result.Result;
} catch (err) {
reject('Ошибка при проверке сертификата: ', err.message);
return;
}
resolve(result);
});
};
/**
* Достает указанное свойство у сертификата
* */
Certificate.prototype.getProp = function (propName) {
var cert = this._cert;
return new Promise(function (resolve, reject) {
var result;
try {
result = cert[propName];
} catch (err) {
reject('Ошибка при обращении к свойству сертификата: ', err.message);
return;
}
resolve(result);
});
};
/**
* Экспорт base64 представления сертификата пользователя
* */
Certificate.prototype.exportBase64 = function exportBase64() {
var cert = this._cert;
return new Promise(function (resolve, reject) {
var base64;
try {
base64 = cert.Export(0);
} catch (err) {
reject('Ошибка при экспорте сертификата: ', err.message);
return;
}
resolve(base64);
});
};
/**
* Возвращает информацию об алгоритме
* */
Certificate.prototype.getAlgorithm = function getAlgorithm() {
var cert = this._cert;
return new Promise(function (resolve, reject) {
var result = {},
algorithm;
try {
algorithm = cert.PublicKey();
algorithm = algorithm.Algorithm;
result.algorithm = algorithm.FriendlyName;
result.oid = algorithm.Value;
} catch (err) {
reject('Ошибка при получении алгоритма: ', err.message);
return;
}
resolve(result);
});
};
/**
* Разбирает SubjectName сертификата по тэгам
* */
Certificate.prototype.getOwnerInfo = function getOwnerInfo() {
return getCertInfo.call(this, cryptoCommon.subjectNameTagsTranslations, 'SubjectName');
};
/**
* Разбирает IssuerName сертификата по тэгам
* */
Certificate.prototype.getIssuerInfo = function getIssuerInfo() {
return getCertInfo.call(this, cryptoCommon.issuerNameTagsTranslations, 'IssuerName');
};
/**
* Получение OID сертификата
* Возвращает массив OID (улучшенного ключа)
* */
Certificate.prototype.getExtendedKeyUsage = function getExtendedKeyUsage() {
var cert = this._cert;
return new Promise(function (resolve, reject) {
var OIDS = [],
count,
item;
try {
count = cert.ExtendedKeyUsage();
count = count.EKUs;
count = count.Count;
if (count > 0) {
while (count > 0) {
item = cert.ExtendedKeyUsage();
item = item.EKUs;
item = item.Item(count);
item = item.OID;
OIDS.push(item);
count--;
}
}
} catch (err) {
reject('Ошибка при получении ОИД\'ов: ', err.message);
return;
}
resolve(OIDS);
});
};
Certificate.prototype.getDecodedExtendedKeyUsage = cryptoCommon.getDecodedExtendedKeyUsage;
Certificate.prototype.hasExtendedKeyUsage = cryptoCommon.hasExtendedKeyUsage;
/**
* Проверяет корректность настроек ЭП на машине
* */
function isValidEDSSettings() {
return new Promise(function (resolve, reject) {
var result;
try {
result = cadesplugin.CreateObject('CAdESCOM.About');
} catch (error) {
reject('Настройки ЭП на данной машине не верны');
}
resolve();
});
}
/**
* Получить сертификат в формате cades по хэшу
* */
function getCadesCert(hash) {
return new Promise(function (resolve, reject) {
var oStore = cadesplugin.CreateObject('CAdESCOM.Store'),
certs,
certCnt,
cert;
if (!oStore) {
reject('Не удалось получить доступ к хранилищу сертификатов');
return;
}
// Открываем хранилище
try {
oStore.Open(
cadesplugin.CAPICOM_CURRENT_USER_STORE,
cadesplugin.CAPICOM_MY_STORE,
cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED
);
} catch (err) {
reject('Ошибка при открытии хранилища: ' + err.message);
return;
}
// Получаем доступ к сертификатам
try {
certs = oStore.Certificates;
certCnt = certs.Count;
} catch (err) {
reject('Ошибка получения списка сертификатов: ' + err.message);
return;
}
if (!certCnt) {
reject('Нет доступных сертификатов');
return;
}
// Получаем сертификат по хэшу
try {
certs = certs.Find(cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, hash);
if (certs.Count) {
cert = certs.Item(1);
} else {
throw new Error(hash);
}
} catch (err) {
reject('Не удалось получить сертификат по хэшу: ' + err.message);
return;
}
oStore.Close();
resolve(cert);
});
}
/**
* Разбирает информацию сертификата по тэгам
* */
function getCertInfo(tags, propName) {
var cert = this._cert;
return new Promise(function (resolve, reject) {
var propInfo;
try {
propInfo = cert[propName];
} catch (err) {
reject('Ошибка при извлечении данных из сертификата: ', err.message);
return;
}
resolve(cryptoCommon.parseCertInfo(tags, propInfo));
});
}
/**
* Возвращает список сертификатов, доступных в системе
*
* @param {Boolean} [resetCache=false] -- нужно ли сбросить кэш списка сертификатов
* @returns {Promise} -- со списком сертификатов {Array}
* */
function getCertsList(resetCache) {
return new Promise(function (resolve, reject) {
if (!resetCache && _certListCache) {
resolve(_certListCache);
return;
}
var oStore = cadesplugin.CreateObject('CAdESCOM.Store'),
result = [],
certs,
count,
item;
// Открываем хранилище
try {
oStore.Open(
cadesplugin.CAPICOM_CURRENT_USER_STORE,
cadesplugin.CAPICOM_MY_STORE,
cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED
);
} catch (err) {
reject('Ошибка при открытии хранилища: ' + err.message);
return;
}
// Получаем доступ к сертификатам
try {
certs = oStore.Certificates;
if (certs) {
certs = certs.Find(cadesplugin.CAPICOM_CERTIFICATE_FIND_TIME_VALID);
/**
* Не рассматриваются сертификаты, в которых отсутствует закрытый ключ
* или не действительны на данный момент
* */
certs = certs.Find(
cadesplugin.CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY,
cryptoConstants.PropId.CAPICOM_PROPID_KEY_PROV_INFO
);
count = certs.Count;
}
} catch (err) {
reject('Ошибка получения списка сертификатов: ' + err.message);
return;
}
if (!count) {
reject('Нет доступных сертификатов');
return;
}
try {
while (count) {
item = certs.Item(count);
result.push(new Certificate({
_cert: item,
thumbprint: item.Thumbprint,
subjectName: item.SubjectName,
issuerName: item.IssuerName,
validFrom: item.ValidFromDate,
validTo: item.ValidToDate
}));
count--;
}
} catch (err) {
reject('Ошибка обработки сертификатов: ' + err.message);
return;
}
oStore.Close();
_certListCache = cryptoCommon.prepareCertsInfo(result);
resolve(_certListCache);
});
}
/**
* Получить сертификат по хэшу
* */
function getCert(hash) {
return new Promise(function (resolve, reject) {
if (!hash) {
reject('Хэш не указан');
return;
}
getCertsList().then(function (list) {
var foundCert;
list.some(function (cert) {
if (hash === cert.thumbprint) {
foundCert = cert;
return true;
}
});
if (foundCert) {
resolve(foundCert);
} else {
reject('Сертификат с хэшем: "' + hash + '" не найден');
}
}, reject);
});
}
/**
* Создает подпись base64 строки по hash'у сертификата
*
* @param {String} hash -- fingerprint (thumbprint) сертификата
* @param {String} dataBase64 -- строковые данные в формате base64
* @param {Boolean} signType -- тип подписи открепленная (true) / присоединенная (false) (default: true)
* @returns {Promise} -- обещание, которое зарезолвится с данными о подписи {String}
* */
function signData(hash, dataBase64, signType) {
signType = typeof signType === 'undefined' ? true : Boolean(signType);
return new Promise(function (resolve, reject) {
getCadesCert(hash).then(function (cert) {
var clientTime = new Date(),
oAttrs = cadesplugin.CreateObject('CADESCOM.CPAttribute'),
oSignedData = cadesplugin.CreateObject('CAdESCOM.CadesSignedData'),
oSigner = cadesplugin.CreateObject('CAdESCOM.CPSigner'),
attrs,
signature;
clientTime = cryptoCommon.getDateObj(clientTime);
try {
oAttrs.Name = cryptoConstants.Time.AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
oAttrs.Value = clientTime;
} catch (err) {
reject('Ошибка при установке данных подписи: ' + err.message);
return;
}
// Задаем настройки для подписи
try {
oSigner.Certificate = cert;
attrs = oSigner.AuthenticatedAttributes2;
attrs.Add(oAttrs);
oSignedData.ContentEncoding = cadesplugin.CADESCOM_BASE64_TO_BINARY;
oSignedData.Content = dataBase64;
oSigner.Options = cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY;
} catch (err) {
reject('Не удалось установить настройки для подписи: ' + err.message);
return;
}
try {
signature = oSignedData.SignCades(
oSigner,
cadesplugin.CADESCOM_CADES_BES,
signType
);
} catch (err) {
reject('Не удалось создать подпись: ' + err.message);
return;
}
resolve(signature);
}, reject);
});
}
/**
* Создает подпись XML строки по hash'у сертификата
*
* @param {String} hash -- fingerprint (thumbprint) сертификата
* @param {String} dataXML -- данные в формате XML
* @returns {Promise} -- обещание, которое зарезолвится с данными о подписи {String}
* */
function signDataXML(hash, dataXML) {
return new Promise(function (resolve, reject) {
getCadesCert(hash).then(function (cert) {
var oSigner = cadesplugin.CreateObject('CAdESCOM.CPSigner'),
signerXML = cadesplugin.CreateObject('CAdESCOM.SignedXML'),
cnts = cryptoConstants,
signature;
// Задаем настройки для подписи
try {
oSigner.Certificate = cert;
// Добавляем данные для подписи
signerXML.Content = dataXML;
// Устанавливаем тип подписи
signerXML.SignatureType = cnts.SignatureType.CADESCOM_XML_SIGNATURE_TYPE_ENVELOPED;
// Устанавливаем алгоритм подписи
signerXML.SignatureMethod = cnts.GostXmlDSigUrls.XmlDsigGost3410Url;
// Устанавливаем алгоритм хэширования
signerXML.DigestMethod = cnts.GostXmlDSigUrls.XmlDsigGost3411Url;
} catch (err) {
reject('Не удалось установить настройки для подписи: ' + err.message);
return;
}
try {
signature = signerXML.Sign(oSigner);
} catch (err) {
reject('Не удалось создать подпись: ' + err.message);
return;
}
resolve(signature);
}, reject);
});
}
/**
* Возвращает информацию о версии CSP и плагина
* */
function getSystemInfo() {
var sysInfo = cryptoCommon.getEnvInfo();
return new Promise(function (resolve, reject) {
var e;
try {
e = cadesplugin.CreateObject('CAdESCOM.About');
sysInfo.cadesVersion = e.PluginVersion;
// Возможен вызов в ранних версиях в виде sysInfo.cspVersion = e.CSPVersion('', 75);
sysInfo.cspVersion = e.CSPVersion();
if (!sysInfo.cadesVersion) {
sysInfo.cadesVersion = e.Version;
}
sysInfo.cadesVersion = sysInfo.cadesVersion.toString();
sysInfo.cspVersion = sysInfo.cspVersion.toString();
resolve(sysInfo);
} catch (err) {
reject('Ошибка при получении информации о системе: ', err.message);
}
});
}
/**
* Promise обертка для синхронного вызова проверки версии CSP
* */
function isValidCSPVersion(version) {
return new Promise(function (resolve) {
resolve(cryptoCommon.isValidCSPVersion(version));
});
}
/**
* Promise обертка для синхронного вызова проверки версии плагина
* */
function isValidCadesVersion(version) {
return new Promise(function (resolve) {
resolve(cryptoCommon.isValidCadesVersion(version));
});
}
module.exports = {
isValidEDSSettings: isValidEDSSettings,
getCertsList: getCertsList,
getCert: getCert,
signData: signData,
signDataXML: signDataXML,
getSystemInfo: getSystemInfo,
isValidCSPVersion: isValidCSPVersion,
isValidCadesVersion: isValidCadesVersion
};