Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline zhenia  
#1 Оставлено : 6 октября 2017 г. 16:16:39(UTC)
zhenia

Статус: Новичок

Группы: Участники
Зарегистрирован: 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 и подставить в DigestValue
3) Взять хэш от блока SignedInfo подписи
4) Получить подпись хэша от SignedInfo алгоритмом gostr34102001-gostr3411 и поместить в SignatureValue
5) Поместить информацию о сертификате в 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)  | Причина: уточнение конфигурации

Offline zhenia  
#2 Оставлено : 13 октября 2017 г. 17:27:45(UTC)
zhenia

Статус: Новичок

Группы: Участники
Зарегистрирован: 18.09.2017(UTC)
Сообщений: 8
Мужчина
Российская Федерация
Откуда: ЦПС

Сказал «Спасибо»: 1 раз
Правильное представление хэша получить удалось.

Если кому понадобится:
Код:

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( Base64.encode( str ) ).then( function(){
                    oHashedData.Value.then( function( hash ){
                        callback( null, Base64.encode( hash, true ) );
                    }, callback);
                }, callback);
            }, callback);
        }, callback);
    }, callback);
};


Для XML:
Код:

<ns1:MessageTypeSelector xmlns:ns1="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1" Id="SIGNED_BY_CALLER"><ns1:Timestamp>2017-10-09T12:55:49.123+03:00</ns1:Timestamp></ns1:MessageTypeSelector>

Хэш будет такой:
Код:

CoFS5DjNAm30Fp1ft2guIR2QWODpT5xVkwWU26+Uljs=


Остается проблема с подписью по хэшу - получаю ошибку:
Код:

The parameter is incorrect. (0x80070057)

Ошибка возвращается после вызова на строке 15.
Код:

createObject( 'CAdESCOM.RawSignature', function( err, oRawSignature ) {
    if ( err ) {
        callback( err );
    }

    createObject( 'CAdESCOM.HashedData', function( err, hashObject ) {
        if ( err ) {
            callback( err );
        }

        hashValue = Base64.decode( hashValue );

        hashObject.propset_Algorithm( cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411 ).then( function() {
            hashObject.propset_DataEncoding( cadesplugin.CADESCOM_BASE64_TO_BINARY ).then( function() {
                hashObject.SetHashValue( hashValue ).then( function() {
                    oRawSignature.SignHash( hashObject, oCert ).then( function( sRawSignature ) {
                        sRawSignature = utils.reverse( utils.hexToString( sRawSignature ) );
                        callback( null, sRawSignature );
                    }, callback);
                }, callback);
            }, callback);
        }, callback);

    });
});

Не могу понять в какой форме нужно представить хэш...

У меня Windows 7 x64 SP1, КриптоПро CSP 3.6.7491 (СКЗИ 3.6.5364КС1) + КриптоПро .NET 1.0.5065.1 (2013).

Может кто подскажет?

Отредактировано пользователем 16 октября 2017 г. 10:49:17(UTC)  | Причина: уточнение конфигурации

Offline cross  
#3 Оставлено : 18 октября 2017 г. 11:01:37(UTC)
Анатолий Беляев

Статус: Сотрудник

Группы: Администраторы, Участники
Зарегистрирован: 24.11.2009(UTC)
Сообщений: 965
Откуда: Crypto-Pro

Сказал(а) «Спасибо»: 3 раз
Поблагодарили: 174 раз в 152 постах
Цитата:
hashValue = Base64.decode( hashValue );

Может вот тут надо encode вызывать?
Техническую поддержку оказываем тут.
Наша база знаний.
Наша страничка в Instagram.
Offline zhenia  
#4 Оставлено : 18 октября 2017 г. 16:46:19(UTC)
zhenia

Статус: Новичок

Группы: Участники
Зарегистрирован: 18.09.2017(UTC)
Сообщений: 8
Мужчина
Российская Федерация
Откуда: ЦПС

Сказал «Спасибо»: 1 раз
При кодировании получаю это
Код:

hashValue = 'rqKWO6Fytc/CM+HvXWk+CT7dZv/6uCOMdvkQUvBmbnk=';
Base64.encode( hashValue);

"cnFLV082Rnl0Yy9DTStIdlhXaytDVDdkWnYvNnVDT01kdmtRVXZCbWJuaz0="


При декодировании это
Код:

Base64.decode( "rqKWO6Fytc/CM+HvXWk+CT7dZv/6uCOMdvkQUvBmbnk=" );
";ᲵΣ3ᯝI>	>ݦﺸ#춹RমY"

Base64.decode( "rqKWO6Fytc/CM+HvXWk+CT7dZv/6uCOMdvkQUvBmbnk=", true );
"AEA2963BA172B5CFC233E1EF5D693E093EDD66FFFAB8238C76F91052F0666E7940"


Что нужна на вход SetHashValue - бинарник или hex?
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.