Статус: Новичок
Группы: Участники
Зарегистрирован: 18.09.2017(UTC) Сообщений: 8 Откуда: ЦПС Сказал «Спасибо»: 1 раз
|
Здравствуйте! Имеется Windows 7 x64 SP1, КриптоПро CSP 3.6.7491 (СКЗИ 3.6.5364КС1) + КриптоПро .NET 1.0.5065.1 (2013). Имеется XML проходящая проверку на соответствие схемам сервиса СМЭВ (в примере удалена информация о сертификате, что бы не захламляло, и отформатирован текст для наглядности): Код:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1" xmlns:ns1="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1">
<soapenv:Header/>
<soapenv:Body>
<ns:GetRequestRequest>
<ns2:MessageTypeSelector xmlns:ns2="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1" xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1" Id="SIGNED_BY_CALLER">
<ns2:Timestamp>2014-02-11T17:10:03.616+04:00</ns2:Timestamp>
</ns2:MessageTypeSelector>
<!--Optional:-->
<ns:CallerInformationSystemSignature>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
<ds:Reference URI="#SIGNED_BY_CALLER">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:Transform Algorithm="urn://smev-gov-ru/xmldsig/transform"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/>
<ds:DigestValue>iYwGGJIG7q3AuiIBGC8G/Uk50FIIJmC+Vxf24dbh15I=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>EoG4oOy27laTo5/vNL57yBvBXimQkE8NpIXa9XDVAU05tsFgKecdRjsuEOkBVAtSFKmUZZtNs3LNZwmuct5r/g==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate></ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</ns:CallerInformationSystemSignature>
</ns:GetRequestRequest>
</soapenv:Body>
</soapenv:Envelope>
Пытаюсь по аналогии подписать исходное сообщение средствами Browser plug-in: Код:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1" xmlns:ns1="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1">
<soapenv:Header/>
<soapenv:Body>
<ns:GetRequestRequest>
<ns2:MessageTypeSelector xmlns:ns2="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1" xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1" Id="SIGNED_BY_CALLER"><ns2:Timestamp>2014-02-11T17:10:03.616+04:00</ns2:Timestamp></ns2:MessageTypeSelector>
<!--Optional:-->
<ns:CallerInformationSystemSignature></ns:CallerInformationSystemSignature>
</ns:GetRequestRequest>
</soapenv:Body>
</soapenv:Envelope>
Алгоритм действий такой: 1) Применить необходимые трансформации к подписываемому блоку ( блок #SIGNED_BY_CALLER и две трнсфорации - xml-exc-c14n и smev-gov-ru ) 2) Взять хэш от подписываемого блока #SIGNED_BY_CALLER и подставить в DigestValue3) Взять хэш от блока SignedInfo подписи 4) Получить подпись хэша от SignedInfo алгоритмом gostr34102001-gostr3411 и поместить в SignatureValue5) Поместить информацию о сертификате в X509CertificateЗагвоздка у меня уже на п.2 - полученный мной хэш не совпадает с тем что есть в валидном XML. Код:
"iYwGGJIG7q3AuiIBGC8G/Uk50FIIJmC+Vxf24dbh15I="
Привожу фрагмент тестового кода (боевой код работает и синхронном варианте, но в приоритете все таки асинхронный поэтому привожу сборку по нему): Код:
var xml = '<ns2:MessageTypeSelector xmlns:ns2="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1" xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1" Id="SIGNED_BY_CALLER"><ns2:Timestamp>2014-02-11T17:10:03.616+04:00</ns2:Timestamp></ns2:MessageTypeSelector>';
var tempSignedInfo = '<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/><ds:Reference URI="#SIGNED_BY_CALLER"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:Transform Algorithm="urn://smev-gov-ru/xmldsig/transform"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/><ds:DigestValue>{0}</ds:DigestValue></ds:Reference></ds:SignedInfo>';
var tempSignature = '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">{0}<ds:SignatureValue>{1}</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>{2}</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>';
var utils = {
reverse: function (str) {
var newStr = '', i;
for (i = str.length - 1; i >= 0; i--) {
newStr += str.charAt(i);
}
return newStr;
},
d2h: function (d) {
var res = d.toString(16).toUpperCase();
if (res.length == 1) {
res = '0' + res;
}
return res;
},
h2d: function (h) {
return parseInt(h, 16);
},
stringToHex: function (string) {
var hex = '';
for (var i = 0; i < string.length; i++) {
hex += this.d2h(string.charCodeAt(i));
}
return hex;
},
hexToString: function (hex) {
var string = '';
for (var b = 0; b < hex.length; b += 2) {
string += String.fromCharCode(parseInt(hex.substr(b, 2), 16));
}
return string;
}
};
var createObject = function( name, callback ){
cadesplugin.CreateObjectAsync( name ).then( function( obj ) {
callback( null, obj );
}, callback);
};
var getHash = function( str, callback ){
createObject( 'CAdESCOM.HashedData', function( err, oHashedData ){
oHashedData.propset_Algorithm( cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411 ).then( function(){
oHashedData.propset_DataEncoding( cadesplugin.CADESCOM_BASE64_TO_BINARY ).then( function() {
oHashedData.Hash( str ).then( function(){
oHashedData.Value.then( function( hash ){
callback( null, hash );
// callback( null, Base64.encode( utils.reverse( utils.hexToString( hash ) ) ) );
}, callback);
}, callback);
}, callback);
}, callback);
}, callback);
};
var sign = function( certThumbprint, callback ) {
// п.0. ключ по отпечатку
createObject( 'CAPICOM.store', function( err, oStore ){
if (err) return callback( err );
oStore.Open( cadesplugin.CAPICOM_CURRENT_USER_STORE, cadesplugin.CAPICOM_MY_STORE, cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED ).then( function(){
oStore.Certificates.then( function( oCertificates ){
oCertificates.Find( cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certThumbprint ).then( function( oListCertificates ){
oListCertificates.Count.then( function( count ){
if ( count == 0 ) {
return callback( new Error('Сертификат не найден') );
}
oListCertificates.Item(1).then( function( oCert ){
// п.2. хэш от подписываемых данных
getHash( xml, function( err, hashData ) {
if (err) return callback( err );
var sSignedInfo = tempSignedInfo.format( hashData );
// п.3.хэш блока подписи
getHash( sSignedInfo, function( err, hashSignedInfo ) {
if (err) return callback( err );
// п.4. подпись хэша
createObject( 'CAdESCOM.RawSignature', function( err, oRawSignature ) {
if (err) return callback( err );
// задаем ранее посчитанный хэш
createObject( 'CAdESCOM.HashedData', function( err, oHashedData ) {
if (err) return callback( err );
oHashedData.propset_Algorithm( cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411 ).then( function() {
oHashedData.propset_DataEncoding( cadesplugin.CADESCOM_BASE64_TO_BINARY ).then( function() {
oHashedData.SetHashValue( hashSignedInfo ).then( function() {
// п.5. подписывание хэша
oRawSignature.SignHash( oHashedData, oCert ).then( function( sRawSignature ) {
// собираем блок подписи
var sSignature = tempSignature.format( sSignedInfo, hashSignedInfo, sRawSignature );
callback( null, sSignature );
}, callback);
}, callback);
}, callback);
}, callback);
});
});
});
});
}, callback);
}, callback);
}, callback);
}, callback);
}, callback);
}, callback);
};
Для проверки правильной работы Base64 привожу пример (кстати, на вход функции подается значения хэша возвращаемое приведенной функцией getHash от константной строки xml): Код:
Base64.encode( '981E5F3CA30C841487830F84FB433E13AC1101569B9C13584AC483234CD656C0' )
"OTgxRTVGM0NBMzBDODQxNDg3ODMwRjg0RkI0MzNFMTNBQzExMDE1NjlCOUMxMzU4NEFDNDgzMjM0Q0Q2NTZDMA=="
При использовании закомментрованной строки возврата хэша на выходе хэш получается такой Код:
callback( null, Base64.encode( utils.reverse( utils.hexToString( hash ) ) ) );
"w4BWw5ZMI8KDw4RKWBPCnMKbVgERwqwTPkPDu8KED8KDwocUwoQMwqM8Xx7CmA=="
Вопросы следующие: 1) Как получить правильное представление хэша ? 2) Почему на п.5. может возникать ошибка "Invalid algorithm specified. (0x80090008)" (а с закомментированным вариантом возврата хэша - "The data is invalid. (0x8007000D)") ? Отредактировано пользователем 16 октября 2017 г. 9:23:26(UTC)
| Причина: уточнение конфигурации
|