Здравствуйте!
Не могу понять как сделать подписывание XML на JavaScript средствами "
КриптоПро ЭЦП Browser plug-in"...
На c# было проще, введу наличия класса signedXml который и канонизировал XML и подписывал его.
А тут, в
КриптоПро ЭЦП Browser plug-in, как я понял, такой возможности нет, ну или пока нет.
Согласно "Методические рекомендации по разработке электронных сервисов и применению ЭЦП при МЭВ" XML должна иметь примерно такую форму
Код:<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ws="http://ws.unisoft/" xmlns:rev="http://smev.gosuslugi.ru/rev120315" xmlns:rq1="http://ws.unisoft/CPSSubsidPercent/Rq1" xmlns:inc="http://www.w3.org/2004/08/xop/include">
<soapenv:Header>
<wsse:Security soapenv:actor="http://smev.gosuslugi.ru/actors/smev">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="SenderCertificate"> ..... </wsse:BinarySecurityToken>
<ds:Signature>
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411" />
<Reference URI="#body">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411" />
<DigestValue> ..... </DigestValue>
</Reference>
</SignedInfo>
<ds:SignatureValue> ..... </ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#SenderCertificate" />
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</soapenv:Header>
<soapenv:Body wsu:Id="body">
<ws:async_getId_SendRequest_Tyrim_Pyrim>
<rev:Message>
<rev:Sender>
<rev:Code> .... </rev:Code>
<rev:Name> .... </rev:Name>
</rev:Sender>
<rev:Recipient>
<rev:Code> .... </rev:Code>
<rev:Name> .... </rev:Name>
</rev:Recipient>
<rev:Originator>
<rev:Code> .... </rev:Code>
<rev:Name> .... </rev:Name>
</rev:Originator>
<rev:ServiceName> .... </rev:ServiceName>
<rev:TypeCode> .... </rev:TypeCode>
<rev:Status> .... </rev:Status>
<rev:Date> 2012-03-12T12:12:12Z </rev:Date>
<rev:ExchangeType> .... </rev:ExchangeType>
<rev:RequestIdRef />
<rev:OriginRequestIdRef />
<rev:ServiceCode />
<rev:CaseNumber />
<rev:TestMsg />
</rev:Message>
<rev:MessageData>
<rev:AppData>
<rq1:Документ ВерсияФормата="1.0" UIDЗапроса="00000000-0000-4000-y000-000000000000">
...
</rq1:Документ>
</rev:AppData>
<rev:AppDocument>
<rev:RequestCode>req_00000000-0000-4000-y000-000000000000</rev:RequestCode>
<rev:BinaryData> ... </rev:BinaryData>
</rev:AppDocument>
</rev:MessageData>
</ws:async_getId_SendRequest_Tyrim_Pyrim>
</soapenv:Body>
</soapenv:Envelope>
По крайней мере в таком виде XML (подписанная C#, в результате чего она записывается в одну строку) проверка на ГосУслугах, что собственно и нужно...
Так вот, мне теперь нужно сформировать XML проходящею валидацию на ГосУслугах средствами JavaScript.
Делаю на основе
soapclient.js.
Непонятно несколько моментов... В начале я их опишу парой слов, а потом скажу как я пытался разрешить эти моменты, к сожалению не особо успешно...
- Достаточно ли записать эту XML в строку (убрав пробелы между тегами и крайние пробелы в значения тегов) что бы она приобрела канонический вид (xml-exc-c14n) ?
- В методических рекомендациях о BinarySecurityToken сказано "Формат сертификата должен соответствовать спецификации X.509 и быть представленным в формате Base64"
- В методических рекомендациях сказано "К элементу <soapenv:Body> и его потомкам, включая атрибуты, применяется каноникализация http://www.w3.org/2001/10/xml-exc-c14n#, на основе результата рассчитывается хеш по алгоритму ГОСТ Р 34.11-94 и заносится в <ds:DigestValue> в формате Base64"
- В методических рекомендациях сказано "К элементу <ds:SignedInfo> и его потомкам, включая атрибуты, применяется каноникализация http://www.w3.org/2001/10/xml-exc-c14n#, на основе результата рассчитывается электронная подпись по алгоритму ГОСТ Р 34.11-2001 и заносится в <ds:SignatureValue> в формате Base64"
Я понял это так:
- Рассчитываю на основе примера "Создание и проверка подписи":
Цитата:// certSubjectName - хеш ключа
// dataToSign - записанный в строку тэг soapenv:Body вместо со всем содержимым
//
function SignCreate(certSubjectName, dataToSign, TSPaddr) {
try {
var oStore = ObjCreator("CAPICOM.store");
oStore.Open();
} catch (err) {
alert('Не удалось создать CAPICOM.store: ' + GetErrorMessage(err));
return;
};
var CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
var oCerts = oStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certSubjectName);
if (oCerts.Count == 0) {
alert("Сертификат не найден");
return;
};
var oCert = oCerts.Item(1);
try {
var oSigner = ObjCreator("CAdESCOM.CPSigner");
} catch (err) {
alert('Не удалось создать CAdESCOM.CPSigner: ' + GetErrorMessage(err));
return;
};
if (oSigner) {
oSigner.Certificate = oCert;
} else {
alert("Не удалось создать CPSigner!");
return;
};
var oSignedData = ObjCreator("CAdESCOM.CadesSignedData");
try {
if (dataToSign) {
// Данные на подпись ввели
oSignedData.Content = dataToSign;
// Выбираем тип подписи
if (TSPaddr === undefined) {
oSigner.Options = CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN;
try {
var sSignedData = oSignedData.SignCades(oSigner, CADES_BES);
} catch (e) {
alert("Не удалось создать подпись из-за ошибки: " + GetErrorMessage(e));
return;
};
} else {
oSigner.TSAAddress = TSPaddr;
try {
var sSignedData = oSignedData.SignCades(oSigner, CADESCOM_CADES_DEFAULT);
} catch (e) {
alert("Не удалось создать подпись из-за ошибки: " + GetErrorMessage(e));
return;
};
};
};
} catch (err) {
alert("Не удалось создать подпись: " + GetErrorMessage(err));
return;
};
oStore.Close();
return sSignedData;
}
Полученный результат записываю сразу в BinarySecurityToken, так как он больше похож по виду на то что получается после подписывания в C#, хотя и все равно другой...
- DigestValue рассчитываю:
Цитата:var HashedData = ObjCreator("CAdESCOM.HashedData");
HashedData.Hash(<хеш ключа>, <записанный в строку тэг soapenv:Body вместо со всем содержимым, такая же как и для расчета
BinarySecurityToken>);
// Преобразую полученный кеш (
HashedData.Value) как посоветовал
Slavik17 в посте
#327 (темы
КриптоПро ЭЦП Browser plug-in)
// Результат преобразования записываю в
DigestValue
- Затем рассчитываю SignatureValue:
Цитата:// Функции передаю хеш ключа, тот же что и SignCreate (из
примера)
// и записанный в строку тег
SignedInfo со всем содержимым
function GetSignatureValue(certSubjectName, dataToSign) {
try {
var oHashedData = ObjCreator("CAdESCOM.HashedData");
oHashedData.Hash(dataToSign);
} catch (err) {
alert('Не удалось создать CAPICOM.HashedData: ' + GetErrorMessage(err));
return;
}
try {
var oStore = ObjCreator("CAPICOM.store");
oStore.Open();
} catch (err) {
alert('Не удалось создать CAPICOM.store: ' + GetErrorMessage(err));
return;
};
var CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
var oCerts = oStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certSubjectName);
if (oCerts.Count == 0) {
alert("Сертификат не найден");
return;
};
var oCert = oCerts.Item(1);
try {
var oRawSignature = ObjCreator("CAdESCOM.RawSignature");
} catch (err) {
alert('Не удалось создать CAdESCOM.RawSignature: ' + GetErrorMessage(err));
return;
};
if (oRawSignature) {
return oRawSignature.SignHash(oHashedData, oCert);
} else {
alert("Не удалось создать RawSignature!");
return;
}
}
На сновании того что у меня ни
BinarySecurityToken, ни SignatureValue, ни даже DigestValue не совдают с теми что получились при подписывании через C#...
Так как в C# подписывание XML по сути скрыто в объекте
SignedXml у меня возникли подозрения, что я все три эти значения, необходимые для подписи я получаю если и абсолютно не верно, то по крайней мере не совсем правильно...
В связи с этим прошу помощи у тех кто с этим разобрался, хотя бы частично...
PS Если данная информация уже где-то есть, то я её не нашел.
Особенно принимая во внимание что не все разделы
справки открываются (некоторые страницы у меня открываются пустыми).
Да и примеров в справке уж очень мало.
Отредактировано пользователем 3 апреля 2013 г. 14:55:01(UTC)
| Причина: Завершение вопроса, после случайного сохранения не полностью набранного вопроса