Статус: Участник
Группы: Участники
Зарегистрирован: 01.04.2013(UTC) Сообщений: 17 Откуда: ООО "ЦентрПрограммСистем" Сказал «Спасибо»: 8 раз
|
Цитата:Берете нужный узел, при помощи, например, c14n приводите к каноническому виду - хэш-значение должно совпадать. Уже пробовал (взял код второго примера, изменил LoadProducts что бы она возвращала записанную в строку XML для подписи (всю, так как с фрагментом не вышло - ругается на не определенное пространство имен soapenv и т.д.)) Цитата:var HashedData = ObjCreator("CAdESCOM.HashedData"); HashedData.DataEncoding = CADESCOM_BASE64_TO_BINARY; HashedData.Algorithm = 100;
HashedData.Hash( Base64.encode('<soapenv:Body wsu:Id="body"><ws:async_getId_SendRequest_Tyrim_Pyrim><rev:Message><rev:Sender><rev:Code>CODE63544</rev:Code><rev:Name>ТутИмя</rev:Name></rev:Sender><rev:Recipient><rev:Code>CODE2</rev:Code><rev:Name>Тест</rev:Name></rev:Recipient><rev:Originator><rev:Code>CODE3</rev:Code><rev:Name>Тест</rev:Name></rev:Originator><rev:ServiceName>ТестВебСервис</rev:ServiceName><rev:TypeCode>GSRV</rev:TypeCode><rev:Status>REQUEST</rev:Status><rev:Date>2012-03-13T12:12:12Z</rev:Date><rev:ExchangeType>1</rev:ExchangeType><rev:RequestIdRef></rev:RequestIdRef><rev:OriginRequestIdRef></rev:OriginRequestIdRef><rev:ServiceCode></rev:ServiceCode><rev:CaseNumber></rev:CaseNumber><rev:TestMsg></rev:TestMsg></rev:Message><rev:MessageData><rev:AppData><rq1:Документ UIDЗапроса="4832bdef-bef7-459a-8397-dc28793f59d4" ВерсияФормата="1.0"><РегНомер>1</РегНомер></rq1:Документ></rev:AppData><rev:AppDocument><rev:RequestCode>req_4832bdef-bef7-459a-8397-dc28793f59d4</rev:RequestCode><rev:BinaryData>UEsDBBQAAAAIABm=</rev:BinaryData></rev:AppDocument></rev:MessageData></ws:async_getId_SendRequest_Tyrim_Pyrim></soapenv:Body>') );
HashedData.Value => "FE93631A13464984BD2BAC4D3DF46D1E1199C2466AD163592EEB98A0762FBB27"
Base64.encode(HashedData.Value, true) => "/pNjGhNGSYS9K6xNPfRtHhGZwkZq0WNZLuuYoHYvuyc=" (это строку HashedData.Value из 64 символа преобразует в массив из 32 байт и работает с ним) Base64.encode(HashedData.Value) => "RkU5MzYzMUExMzQ2NDk4NEJEMkJBQzREM0RGNDZEMUUxMTk5QzI0NjZBRDE2MzU5MkVFQjk4QTA3NjJGQkIyNw==" Если меняю в ShowTransformProperties меняю Цитата:XmlDsigC14NTransform на Цитата:XmlDsigExcC14NTransform то Цитата:var HashedData = ObjCreator("CAdESCOM.HashedData"); HashedData.DataEncoding = CADESCOM_BASE64_TO_BINARY; HashedData.Algorithm = 100;
HashedData.Hash( Base64.encode('<soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="body"><ws:async_getId_SendRequest_Tyrim_Pyrim xmlns:ws="http://ws.unisoft/"><rev:Message xmlns:rev="http://smev.gosuslugi.ru/rev120315"><rev:Sender><rev:Code>CODE63544</rev:Code><rev:Name>ТутИмя</rev:Name></rev:Sender><rev:Recipient><rev:Code>CODE2</rev:Code><rev:Name>Тест</rev:Name></rev:Recipient><rev:Originator><rev:Code>CODE3</rev:Code><rev:Name>Тест</rev:Name></rev:Originator><rev:ServiceName>ТестВебСервис</rev:ServiceName><rev:TypeCode>GSRV</rev:TypeCode><rev:Status>REQUEST</rev:Status><rev:Date>2012-03-13T12:12:12Z</rev:Date><rev:ExchangeType>1</rev:ExchangeType><rev:RequestIdRef></rev:RequestIdRef><rev:OriginRequestIdRef></rev:OriginRequestIdRef><rev:ServiceCode></rev:ServiceCode><rev:CaseNumber></rev:CaseNumber><rev:TestMsg></rev:TestMsg></rev:Message><rev:MessageData xmlns:rev="http://smev.gosuslugi.ru/rev120315"><rev:AppData><rq1:Документ xmlns:rq1="http://ws.unisoft/CPSSubsidPercent/Rq1" UIDЗапроса="4832bdef-bef7-459a-8397-dc28793f59d4" ВерсияФормата="1.0"><РегНомер>1</РегНомер></rq1:Документ></rev:AppData><rev:AppDocument><rev:RequestCode>req_4832bdef-bef7-459a-8397-dc28793f59d4</rev:RequestCode><rev:BinaryData>UEsDBBQAAAAIABm=</rev:BinaryData></rev:AppDocument></rev:MessageData></ws:async_getId_SendRequest_Tyrim_Pyrim></soapenv:Body>') );
HashedData.Value => "BBA8EC92558050A357A40B5502098BE394075C3D4F233A874344D3CB8240230F"
Base64.encode(HashedData.Value, true) => "u6jsklWAUKNXpAtVAgmL45QHXD1PIzqHQ0TTy4JAIw8=" (это строку HashedData.Value из 64 символа преобразует в массив из 32 байт и работает с ним) Base64.encode(HashedData.Value) => "QkJBOEVDOTI1NTgwNTBBMzU3QTQwQjU1MDIwOThCRTM5NDA3NUMzRDRGMjMzQTg3NDM0NEQzQ0I4MjQwMjMwRg==" то есть не совпадает с Цитата:M64fZJNYE9Cb4kLc16P40/r+416DTzbJjcibm0voZOo= это значение устанавливает следующий функция: Цитата: void SignXmlFile(string FileName, string SignedFileName, String thumbprint, String pass) { X509Store certStore = new X509Store(StoreLocation.CurrentUser); certStore.Open(OpenFlags.ReadWrite); X509Certificate2Collection validCerts = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false); if (validCerts.Count == 1) { X509Certificate2 Certificate = validCerts[0]; System.Xml.XmlDocument doc = new XmlDocument(); doc.PreserveWhitespace = false; doc.Load(new XmlTextReader(FileName));
Gost3410CryptoServiceProvider cert_key = Certificate.PrivateKey as Gost3410CryptoServiceProvider; if (null != cert_key) { var cspParameters = new CspParameters(); //копируем параметры csp из исходного контекста сертификата cspParameters.KeyContainerName = cert_key.CspKeyContainerInfo.KeyContainerName; cspParameters.ProviderType = cert_key.CspKeyContainerInfo.ProviderType; cspParameters.ProviderName = cert_key.CspKeyContainerInfo.ProviderName; cspParameters.Flags = cert_key.CspKeyContainerInfo.MachineKeyStore ? (CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore) : (CspProviderFlags.UseExistingKey); cspParameters.KeyPassword = new SecureString(); foreach (var c in pass) { cspParameters.KeyPassword.AppendChar(c); } //задаем криптопровайдер с установленным паролем Certificate.PrivateKey = new Gost3410CryptoServiceProvider(cspParameters); }
// Класс с перегруженным GetIdElement для корректной обработки wsu:Id MySignedXml signedXml = new MySignedXml(doc); signedXml.SigningKey = Certificate.PrivateKey; Reference reference = new Reference(); reference.Uri = "#body";
#pragma warning disable 612 //warning CS0612: 'CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete' is obsolete reference.DigestMethod = CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete; #pragma warning restore 612
//XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); //reference.AddTransform(env); XmlDsigExcC14NTransform c14 = new XmlDsigExcC14NTransform(); reference.AddTransform(c14); signedXml.AddReference(reference); KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(Certificate)); signedXml.KeyInfo = keyInfo; signedXml.SignedInfo.CanonicalizationMethod = c14.Algorithm;
#pragma warning disable 612 //warning CS0612: 'CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete' is obsolete signedXml.SignedInfo.SignatureMethod = CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3410UrlObsolete; #pragma warning restore 612
signedXml.ComputeSignature(); XmlElement xmlDigitalSignature = signedXml.GetXml(); doc.GetElementsByTagName("ds:Signature")[0].PrependChild(doc.ImportNode(xmlDigitalSignature.GetElementsByTagName("SignatureValue")[0], true)); doc.GetElementsByTagName("ds:Signature")[0].PrependChild(doc.ImportNode(xmlDigitalSignature.GetElementsByTagName("SignedInfo")[0], true)); doc.GetElementsByTagName("wsse:BinarySecurityToken")[0].InnerText = xmlDigitalSignature.GetElementsByTagName("X509Certificate")[0].InnerText;
//doc.Save(SignedFileName); using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false))) { doc.WriteTo(xmltw); } } }
Подпись проходит проверку на http://smev.gosuslugi.ru/portal/services-tools.jspА с данными на основе приведенного в начале посте кэша - нет Если предположить что хотя бы BinarySecurityToken устанавливается верно Цитата:function GetCert(certSubjectName) { // сюда передаётся отпечаток try { var oStore = ObjCreator("CAPICOM.store"); oStore.Open(); } catch (err) { alert('Не удалось создать CAPICOM.store: ' + GetErrorMessage(err)); return; }; var oCerts = oStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certSubjectName); if (oCerts.Count == 0) { alert("Сертификат не найден"); return; }; return oStore.Certificates.Item(1).Export(CAPICOM_ENCODE_BASE64); } То тогда получается что кэш рассчитывается на правильно, да же если канонизация правильная (или наоборот, не верно канонизируется при правильном расчете кэша). Кстати, кэш у меня рассчитывается так: Цитата:var Base64 = { // приватное свойство _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// публичный метод кодирования в base64 (если hexToBin = true, то входная строковая запись хеша (шестнадцатеричная строка) перекодируется в последовательность байт) encode : function (input, hexToBin) { var output = ""; var bytes, chr1, chr2, chr3, enc1, enc2, enc3, enc4; input = Base64._utf8_encode(input); if (hexToBin) bytes = Base64.hexToBin(input); var i = 0; while ((hexToBin && (i < bytes.length)) || (!hexToBin && (i < input.length))) { if (hexToBin) { chr1 = bytes[i++]; chr2 = bytes[i++]; chr3 = bytes[i++]; } else { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); }; enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output += this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); } return output; }, // публичный метод декодирования из base64 (если hexToBin = true, то результат (из последовательности байт) перекодируется в строковую запись (шестнадцатеричная строка)) decode : function (input, binToHex) { var output = ""; var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0; input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); while (i < input.length) { enc1 = this._keyStr.indexOf(input.charAt(i++)); enc2 = this._keyStr.indexOf(input.charAt(i++)); enc3 = this._keyStr.indexOf(input.charAt(i++)); enc4 = this._keyStr.indexOf(input.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; if (binToHex) { output += Base64.binToHex( [chr1, chr2, chr3] ); } else { output += String.fromCharCode(chr1); if (enc3 != 64) { output += String.fromCharCode(chr2); } if (enc4 != 64) { output += String.fromCharCode(chr3); } }; } output = Base64._utf8_decode(output); return output.toUpperCase(); },
// публичный метод перекодирования строковой записи хеша (шестнадцатеричной строки без разделителей) в последовательность байт (массив) hexToBin : function (input) { var bytes = []; for (var i = 0, l = input.length; i < l; i += 2) { bytes.push( parseInt( input.substr(i, 2), 16 ) ); }; return bytes; },
// публичный метод перекодирования последовательности байт (массива) в строковую запись хеша (шестнадцатеричную строку без разделителей) binToHex : function (input) { var str = "", s; for (var i = 0, l = input.length; i < l; i++) { s = input[i].toString(16); str += (s.length == 1 ? "0" : "") + s; }; return str; }, // припатный метод для кодирования UTF-8 _utf8_encode : function (string) { string = string.replace(/\r\n/g,"\n"); var utftext = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; }, // приватный метод для декодирования UTF-8 _utf8_decode : function (utftext) { var string = ""; var i = 0; var c = c1 = c2 = 0; while ( i < utftext.length ) { c = utftext.charCodeAt(i); if (c < 128) { string += String.fromCharCode(c); i++; } else if((c > 191) && (c < 224)) { c2 = utftext.charCodeAt(i+1); string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); i += 2; } else { c2 = utftext.charCodeAt(i+1); c3 = utftext.charCodeAt(i+2); string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); i += 3; } } return string; } } Если нужна другая функция Base64, то пожалуйста подскажите какая... Отредактировано пользователем 10 апреля 2013 г. 11:34:32(UTC)
| Причина: Не указана
|