AlexMAS / GostCryptography

.NET driver for ViPNet CSP and CryptoPro CSP
MIT License
133 stars 42 forks source link

ЭЛН 2.0 #39

Open spiridonovav opened 3 years ago

spiridonovav commented 3 years ago

Здравствуйте, коллеги! С 2017 года используем GostCryptography для взаимодействия с ФСС в части обмена данными ЭЛН. За библиотеку Автору отдельное спасибо. Все прекрасно работало, до появления сервиса версии 2.0.

С появлением нового сервиса, на запрос ЭЛН по № и СНИЛС (в тестовый контур https://docs-test.fss.ru/ws-insurer-crypto-v20/FileOperationsLnService), всегда возвращается ошибка: "ru.fss.integration.ws.fault.v01.InternalException: Не удалось расшифровать сообщение. Возможно сообщение зашифровано на ключе отличном от ключа уполномоченного лица ФСС. Проверьте правильность и актуальность ключа уполномоченного лица ФСС. class ru.ibs.cryptopro.jcp.eln.crypt.CryptoException".

В процессе отладки удалось выяснить, что тестовый контур ЭЛН 2.0 не принимает сертификат уполномоченного лица ФСС для тестового контура (https://cabinets-test.fss.ru/FSS_TEST_CERT_2021.cer), а только сертификат для рабочего контура (https://cabinets.fss.ru/FSS_PROD_CERT_2021.cer). Также тестовый контур 2.0 (в отличии от тестового контура 1.1) не принимает тестовые сертификаты (выданные тестовыми УЦ), а только выданные акредитованными УЦ (т.е. полноценные сертификаты).

При выполнении этих условий АРМ ФСС выполняет запрос ЭЛН по № и СНИЛС и ему сервис возвращает: "Ошибка: ORA-20001: Некорректные параметры: Рег. номер в запросе и ОГРН в сертификате ЭП. Не найден страхователь с такими параметрами, а также отсутствует уполномоченный представитель с таким сертификатом ЭП". Что, в общем корректно (если не обращать внимание, что контур тестовый), так как используется сертификат страхователя, который не участвует в обмене данными ЭЛН.

Запрос в тестовый контур ЭЛН 2.0 без шифрования данных (https://docs-test.fss.ru/ws-insurer-v20/FileOperationsLnService) выполняется и сервис возвращает: "ORA-20001: Номер 306735316028 принадлежит к ЛН на бумажном бланке". Что тоже выглядит корректно. То есть, на лицо проблема с шифрованием (или расшифровыванием на стороне ФСС) сообщения.

Код метода и текст сообщения, передаваемое сервису ФСС в следующих сообщениях.

Кто ни будь подскажите, в чем моя ошибка.

spiridonovav commented 3 years ago

Код метода шифрования:

` var publicKeyFSS = (GostAsymmetricAlgorithm)fssCert.GetPublicKeyAlgorithm(); var element = (XmlElement)elements[0]; // Создание случайного сессионного ключа using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm()) { // Шифрация элемента var encryptedData = encryptedXml.EncryptData(element, sessionKey, false);

                // Шифрация сессионного ключа с использованием общего симметричного ключа
                var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, publicKeyFSS);

                // Формирование элемента EncryptedData
                var elementEncryptedData = new EncryptedData();
                elementEncryptedData.Id = "EncryptedElement1";
                elementEncryptedData.Type = EncryptedXml.XmlEncElementContentUrl;
                elementEncryptedData.EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName);
                elementEncryptedData.CipherData.CipherValue = encryptedData;
                elementEncryptedData.KeyInfo = new KeyInfo();

                // Формирование информации о зашифрованном сессионном ключе
                var encryptedSessionKey = new EncryptedKey();
                encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
                //ФСС использует устаревший идентификатор
                //encryptedSessionKey.EncryptionMethod = new EncryptionMethod(publicKey.KeyExchangeAlgorithm);
                encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostCryptography.Gost_R3410.Gost_R3410_2001_AsymmetricAlgorithm.KeyExchangeAlgorithmValue);
                encryptedSessionKey.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });
                //encryptedSessionKey.KeyInfo.AddClause(new KeyInfoName { Value = "SharedKey1" });
                encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(insCert));

                // Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
                elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));

                var newDoc = new XmlDocument() { PreserveWhitespace = true };
                newDoc.LoadXml(SOAPMessageStr);

                // Замена элемента его зашифрованным представлением
                GostEncryptedXml.ReplaceElement((XmlElement)newDoc.GetElementsByTagName("Body", xmlsoapNamespace)[0], elementEncryptedData, true);

                return newDoc;
            }`
spiridonovav commented 3 years ago

Текст зашифрованного сообщения: <?xml version="1.0" encoding="UTF-8"?> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header /> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><EncryptedData Id="EncryptedElement1" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns="http://www.w3.org/2001/04/xmlenc#"><EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gost28147" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"><EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><X509Data><X509Certificate>...</X509Certificate></X509Data></KeyInfo><CipherData><CipherValue>...</CipherValue></CipherData><ReferenceList><DataReference URI="#EncryptedElement1" /></ReferenceList></EncryptedKey></KeyInfo><CipherData><CipherValue>...</CipherValue></CipherData></EncryptedData></s:Body> </s:Envelope>

AlexMAS commented 3 years ago

Здравствуйте. Насколько я помню, ранее была проблема с использованием устаревшего ID. Возможно они изменили что-то в этой части.

//ФСС использует устаревший идентификатор
//encryptedSessionKey.EncryptionMethod = new EncryptionMethod(publicKey.KeyExchangeAlgorithm);

encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostCryptography.Gost_R3410.Gost_R3410_2001_AsymmetricAlgorithm.KeyExchangeAlgorithmValue);
DPonomarchuk commented 3 years ago

Я занимался сервисом МО, а не страхователя, но для меня это работает так: 1) При отправке запроса с шифрованием проверьте что в <Header></Header> исходного сообщения (еще до шифрования) добавлен тег <X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#"></X509Certificate> содержащий ваш тестовый сертификат 2) Взаимодействие с сервисом с шифрованием https://docs-test.fss.ru/WSLnCryptoV20/FileOperationsLnService?WSDL работает именно с сертификатом https://docs-test.fss.ru/FSS_TEST_CERT_2021.cer 3) Тестовый контур принимает тестовые сертификаты Vipnet http://testcert.infotecs.ru/ . Был какой-то период, что они удалили на тестовом контуре сертификат УЦ из доверенных и отбраковывали тестовые сертификаты по "ошибка построения цепочки...".

Я считаю что если шифрование работало в версии 1.1, то вам нужно написать в чат разработчиков ФСС в телеграмм (возможно там кто-то сталкивался с таким) и ваша проблема не имеет отношения к библиотеке GostCryptography

Моё зашифрованное сообщение выглядит так: `

<SOAP-ENV:Body>
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#">
        <EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gost28147"/>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
                <EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001"/>
                <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                    <X509Data>
                        <X509Certificate></X509Certificate>
                    </X509Data>
                </KeyInfo>
                <CipherData>
                    <CipherValue></CipherValue>
                </CipherData>
            </EncryptedKey>
        </KeyInfo>
        <CipherData>
            <CipherValue></CipherValue>
        </CipherData>
    </EncryptedData>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope> `

spiridonovav commented 3 years ago

Большое спасибо за ответ.

Я занимался сервисом МО, а не страхователя, но для меня это работает так:

  1. При отправке запроса с шифрованием проверьте что в <Header></Header> исходного сообщения (еще до шифрования) добавлен тег <X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#"></X509Certificate> содержащий ваш тестовый сертификат

Я не внимательно прочитал спецификацию 2.0. После сравнения текстов 1.1 с 2.0 я увидел, что они перенесли сертификат отправителя (страхователя) в тело шифруемого сообщения, а в KeyInfo нужно класть сертификат уполномоченного лица ФСС. Это я исправил, сервис стал выдавать такую ошибку: "ru.fss.integration.ws.fault.v01.InternalException: Error in execution of data encrypting/decrypting operation. class org.apache.xml.security.encryption.XMLEncryptionException."

Возможно я неправильно помещаю свой сертификат в Header? В спецификации об этом написано (в двух местах) так:

  1. "В блоке в подписанном запросе добавляется блок , который содержит публичный сертификат пользователя в формате x509v3 (кодировке base64)."
  2. "В блоке исходного шифруемого сообщения необходимо добавить блок , содержащий публичный ключ сертификата отправителя. Структура сообщения для шифрования после этого будет выглядеть следующим образом:"

Я это делал двумя способами: var bsToken = request.CreateElement("", "X509Certificate", "http://www.w3.org/2000/09/xmldsig#"); bsToken.InnerText = Convert.ToBase64String(insCert.GetPublicKey()); //bsToken.InnerText = Convert.ToBase64String(insCert.RawData); header[0].AppendChild(bsToken);

  1. Взаимодействие с сервисом с шифрованием https://docs-test.fss.ru/WSLnCryptoV20/FileOperationsLnService?WSDL работает именно с сертификатом https://docs-test.fss.ru/FSS_TEST_CERT_2021.cer
  2. Тестовый контур принимает тестовые сертификаты Vipnet http://testcert.infotecs.ru/ . Был какой-то период, что они удалили на тестовом контуре сертификат УЦ из доверенных и отбраковывали тестовые сертификаты по "ошибка построения цепочки...".

Да, АРМ ЛПУ работает с тестовыми сертификатами. АРМ ФСС (подготовка расчетов для ФСС) получает от сервиса ошибку, в случае использования тестового сертификата: "Ошибка: ORA-20001: Некорректная подпись головной организации: Ошибка при проверке сертификата. VALID_SIGNATURE ЭП действительна; При проверке сертификата ЭП произошла ошибка. Ошибка построения цепочки сертификатов. Не найден сертификат Удостоверяющего Центра, указанный в сертификате пользователя". Либо АРМ ФСС игнорирует настройку "направление обмена" и работает только с рабочим контуром или тестовый контур не принимает тестовые сертификаты.

Я считаю что если шифрование работало в версии 1.1, то вам нужно написать в чат разработчиков ФСС в телеграмм (возможно там кто-то сталкивался с таким) и ваша проблема не имеет отношения к библиотеке GostCryptography

Единственный телеграмм канал ФСС, который я обнаружил - FSS_Info. Так там одни новости от ФСС и никакой технической информации. Подскажите, какой канал вы имели в виду?

spiridonovav commented 3 years ago

Здравствуйте. Насколько я помню, ранее была проблема с использованием устаревшего ID. Возможно они изменили что-то в этой части.

Если использовать другой идентификатор, то от сервиса возвращается ошибка: "ru.fss.integration.ws.fault.v01.InternalException: Не удалось расшифровать сообщение. Возможно сообщение зашифровано на ключе отличном от ключа уполномоченного лица ФСС. Проверьте правильность и актуальность ключа уполномоченного лица ФСС."

spiridonovav commented 3 years ago

Полный текст последнего варианта процедуры шифрования:

`var publicKeyFSS = (GostAsymmetricAlgorithm)fssCert.GetPublicKeyAlgorithm(); var element = (XmlElement)elements[0]; var header = request.GetElementsByTagName("Header", xmlsoapNamespace); ; if (header.Count > 0) { var bsToken = request.CreateElement("", "X509Certificate", "http://www.w3.org/2000/09/xmldsig#"); bsToken.InnerText = Convert.ToBase64String(insCert.GetPublicKey()); //bsToken.InnerText = Convert.ToBase64String(insCert.RawData); header[0].AppendChild(bsToken); } // Создание случайного сессионного ключа using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm()) { // Шифрация элемента var encryptedData = encryptedXml.EncryptData(element, sessionKey, false);

                // Шифрация сессионного ключа с использованием общего симметричного ключа
                var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, publicKeyFSS);

                // Формирование элемента EncryptedData
                var elementEncryptedData = new EncryptedData();
                elementEncryptedData.Type = EncryptedXml.XmlEncElementContentUrl;
                //elementEncryptedData.Type = EncryptedXml.XmlEncElementUrl;
                elementEncryptedData.EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName);
                elementEncryptedData.CipherData.CipherValue = encryptedData;
                elementEncryptedData.KeyInfo = new KeyInfo();

                // Формирование информации о зашифрованном сессионном ключе
                var encryptedSessionKey = new EncryptedKey();
                encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
                //ФСС использует устаревший идентификатор
                //encryptedSessionKey.EncryptionMethod = new EncryptionMethod(publicKeyFSS.KeyExchangeAlgorithm);
                encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostCryptography.Gost_R3410.Gost_R3410_2001_AsymmetricAlgorithm.KeyExchangeAlgorithmValue);
                encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(fssCert));

                // Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
                elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));

                var newDoc = new XmlDocument() { PreserveWhitespace = true };
                newDoc.LoadXml(SOAPMessageStr);

                // Замена элемента его зашифрованным представлением
                GostEncryptedXml.ReplaceElement((XmlElement)newDoc.GetElementsByTagName("Body", xmlsoapNamespace)[0], elementEncryptedData, true);

                return newDoc;
            }`
spiridonovav commented 3 years ago

Возможно, ошибка ""ru.fss.integration.ws.fault.v01.InternalException: Error in execution of data encrypting/decrypting operation. class org.apache.xml.security.encryption.XMLEncryptionException.", возникает в сервисе ФСС уже на этапе шифрования ответного сообщения из-за того, что я "неправильно" передаю им свой сертификат? Кто ни будь знает как нужно?

spiridonovav commented 3 years ago

В спецификации написано:

  1. в разделе подписания сообщения: "В блоке soapenv:Header в подписанном запросе добавляется блок , который содержит публичный сертификат пользователя в формате x509v3 (кодировке base64)."
  2. в разделе шифрования сообщения: "В блоке soapenv:Header исходного шифруемого сообщения необходимо добавить блок , содержащий публичный ключ сертификата отправителя. Структура сообщения для шифрования после этого будет выглядеть следующим образом:"

Может нужно добавлять два сертификата? Тогда непонятно, что за сертификат "пользователя"? Сертификат "отправителя" - это, наверное, сертификат страхователя.

spiridonovav commented 3 years ago

Все таки правильный вариант: bsToken.InnerText = Convert.ToBase64String(insCert.RawData); Так получается идентичная строка элемента , что и при использовании: KeyInfoX509Data(insCert)

spiridonovav commented 3 years ago

Моё зашифрованное сообщение выглядит так: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gost28147"/> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001"/> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <X509Data> <X509Certificate></X509Certificate> </X509Data> </KeyInfo> <CipherData> <CipherValue></CipherValue> </CipherData> </EncryptedKey> </KeyInfo> <CipherData> <CipherValue></CipherValue> </CipherData> </EncryptedData> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

Еще я заметил отличие. В вашем примере атрибут Type имеет значение "http://www.w3.org/2001/04/xmlenc#Element". Хотя в документации в примерах указано "http://www.w3.org/2001/04/xmlenc#Content". Но, в моем случае, это никак не влияет на результат.

alexnur commented 3 years ago

Добрый день! Я тоже уже несколько дней пробую получить ЭЛН (сервис страхователя) по спецификации 2.0. Техподдержка ФСС не оказывает содействия в разработке, но на кое какие вопросы отвечает. Касаемо шифрования или примеров - не ответят. Проверено. Вот их почта: lk_test@fss.ru. По спецификации 1.1 я без проблем шифрую запросы и дешифрую ответы от ФСС. С 2.0 - мог только подписать и отправить на тестовый контур без шифрования: https://docs-test.fss.ru/ws-insurer-v20_2/FileOperationsLnService?wsdl Однако этот url уже несколько дней не доступен (404, not found). В поддержку сообщил, ответа пока не было. Пробую также отправить на тестовый контур с шифрованием. Там в запросе ранее было getPrivateLNData, для 2.0 меняется на getPrivateLNDataRequest. Возникает исключение при отправке запроса: 500 ошибка на стороне ФСС. У Вас хотя бы сообщение развернутое приходит. Запрашивал в поддержке тестовый готовый зашифрованный запрос, чтобы исключить остальные проблемы. Прислали зашифрованный запрос. Если я его отправляю на тестовый контур с шифрованием - все хорошо. В перечне изменений некотоыре моменты не уточнены, помимо заголовка шифруемого сообщения. Лучше бы этого перечня изменений не было. Сбивает с толку. Если в перечне изменений чего-то нет, значит вещи не менялись. У них другое понимание. В п.5.1. "Этапы шифрования сообщения", далее 2.1. Указан алгоритм трансформации "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001", а в спецификации 1.1 "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2012". Однако в своей программе в версии 1.1, несмотря на то, что в спецификации указан 2012, у меня было указано именно "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001", и все работало. В общем, давайте вместе пробовать разбираться. Вот мой код: ` // Спецификация 2.0 public class EncryptedXmlSessionKey2: EncryptedXmlSessionKey {

region Шифрование документа по спецификации 2.0.

    /// <summary>
    ///  Шифрование документа по спецификации 2.0.
    /// </summary>
    /// <param name="xmlDocument"> Подписанный ЭЦП XML-документ. </param>
    /// <param name="sharedKey"> var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);</param>
    /// <param name="certificateEncryption"> Публичный сертификат ФСС.</param>
    /// <param name="certificateEncryption"> Публичный сертификат страхователя.</param>
    protected override XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, Gost_28147_89_SymmetricAlgorithmBase sharedKey,
    X509Certificate2 certificateEncryption,
    X509Certificate2 certificateOpen)
    {
        // Сюда будет записан зашифрованный XML-документ "xmlDocument".
        XmlDocument result = new XmlDocument();
        // Согласно спецификации 2.0 необходимо добавить X509Certificate (публичный сертификат пользователя) в header после подписания документа, 
        // но перед шифрованием.
        // Несмотря на то, что этот же сертификат добавлен в header в секцию BinarySecurityToken!
        InsertX509UserPublicCertificateToXmlHeader(xmlDocument, certificateOpen);
        // Ищем заданный элемент для заширования. Envelope
        XmlElement elementToEncrypt = GetElementToEncrypt(xmlDocument, ref result);
        // Создаем объект EncryptedData и заполняем его необходимой информацией.
        EncryptedData edElement = new EncryptedData();
        //edElement.Type = EncryptedXml.XmlEncElementUrl;
        edElement.Type = EncryptedXml.XmlEncElementContentUrl;
        // Заполняем алгоритм зашифрования данных.  Он будет использован при расшифровании.
        edElement.EncryptionMethod = new EncryptionMethod(Gost_28147_89_SymmetricAlgorithm.AlgorithmNameValue);
        // Создаем новую ссылку на ключ.
        edElement.KeyInfo = new KeyInfo();
        // Создаем случайный симметричный ключ.
        // В целях безопасности удаляем ключ из памяти после использования.
        using (Gost_28147_89_SymmetricAlgorithm sessionKey = new Gost_28147_89_SymmetricAlgorithm(sharedKey.ProviderType))
        {
            // Gost_R3410_2001_Constants.SignatureAlgorithm
            //sessionKey.
            //При генерации сессионного ключа 28147 всегда используется 2001 провайдер(TypeId = 75).
            //Соответственно параметры CIPHER_OID ключа всегда берутся для указанного провайдера.
            //И если при шифровании ключа используется новый сертификат ФСС(уполномоченного лица) с
            //2012 ключом получается нехорошо:
            //                -(.
            //В обернутом ключе параметры алгоритма прописываются
            //1.2.643.2.2.31.1
            //когда как ФСС ожидает
            //1.2.643.7.1.2.5.1.1
            // Создаем объект класса EncryptedXml
            EncryptedXml eXml = new EncryptedXml();
            // Зашифроваем узел на симметричном ключе.
            byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
            // Зашифровываем сессионный ключ и добавляем эти зашифрованные данные к узлу EncryptedKey.
            EncryptedKey ek = new EncryptedKey();
            byte[] encryptedKey = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificateEncryption.GetPublicKeyAlgorithm());
            ek.CipherData = new CipherData(encryptedKey);
            //ek.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostNamespaceUrl + "transport-gost2001");
            ek.EncryptionMethod = new EncryptionMethod(GostCryptography.Gost_R3410.Gost_R3410_2001_AsymmetricAlgorithm.KeyExchangeAlgorithmValue);
            KeyInfoX509Data data = new KeyInfoX509Data(certificateOpen);
            ek.KeyInfo.AddClause(data);
            // Добавляем ссылку на зашифрованный ключ к зашифрованным данным.
            edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
            // Добавляем зашифрованные данные к объекту EncryptedData.
            edElement.CipherData.CipherValue = encryptedElement;

        }
        // Заменяем исходный узел на зашифрованный.
        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

        return result;
    }
    #endregion

    private void InsertX509UserPublicCertificateToXmlHeader(XmlDocument xmlDocument, X509Certificate2 certificateOpen)
    {
        XmlNode nodeHeader = xmlDocument.LastChild.ChildNodes[1];
        XmlElement el = xmlDocument.DocumentElement;
        XmlElement elemX509Certificate = xmlDocument.CreateElement("X509Certificate");
        XmlText certX509xmlText = xmlDocument.CreateTextNode(Convert.ToBase64String(certificateOpen.Export(X509ContentType.Cert),
            Base64FormattingOptions.InsertLineBreaks));
        elemX509Certificate.AppendChild(certX509xmlText);
        nodeHeader.AppendChild(elemX509Certificate);
    }

    #region Приватный метод. Получение части XML-документа, которую необходимо зашифровать ("Envelope").
    /// <summary>
    ///  Получение части XML-документа, которую необходимо зашифровать ("Envelope").
    /// </summary>
    /// <param name="xmlDocument"> Подписанный ЭЦП XML-документ. </param>
    /// <param name="xml"> Необходимо передать новый объект XmlDocument как ref. Часть документа ("Envelope") будет ссылаться на новый XML-документ "xml". 
    /// Именно документ "xml" после дальнейшей обработки необходимо будет отправить как зашифрованный.</param>
    protected override XmlElement GetElementToEncrypt(XmlDocument document, ref XmlDocument xml)
    {
        document.PreserveWhitespace = true;
        XmlNode elementBody = document.GetElementsByTagName("Envelope", MyConst.xmlns_soapenv)[0];
        // Создаем новый XML документ.
        XmlDocument doc = new XmlDocument();
        //XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);

        //ns.AddNamespace("soapenv", MyConst.xmlns_soapenv);
        //ns.AddNamespace("xenc", MyConst.xmlns_xenc);
        //ns.AddNamespace("ds", MyConst.xmlns_ds);
        //ns.AddNamespace("sch", MyConst.xmlns_sch);
        //ns.AddNamespace("wsse", MyConst.xmlns_wsse);
        //ns.AddNamespace("wsu", MyConst.xmlns_wsu);

        MemoryStream newRequestStream = new MemoryStream();
        XmlWriter writer = XmlWriter.Create(newRequestStream, new XmlWriterSettings { Encoding = Encoding.UTF8 });
        writer.WriteStartDocument();
        // Envelope 
        writer.WriteStartElement("soapenv", "Envelope", MyConst.xmlns_soapenv);
        //Header 
        writer.WriteStartElement("soapenv", "Header", MyConst.xmlns_soapenv);
        writer.WriteEndElement(); // Header
        writer.WriteStartElement("soapenv", "Body", MyConst.xmlns_soapenv); // Body
        // ************************************************************* EncryptedData ************************************************************************** /
        writer.WriteRaw(elementBody.OuterXml);
        // ******************************************************************************************************************************************************* /
        writer.WriteEndElement(); // Body
        writer.WriteEndElement(); // Envelope
        writer.WriteEndDocument();
        writer.Flush();
        string xmlText = Encoding.GetEncoding("UTF-8").GetString(newRequestStream.ToArray());

      //  xmlText = xmlText.Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");

        newRequestStream.Position = 0;
        xml.Load(newRequestStream);
        writer.Close();
        // Ищем заданный элемент для зашифрования. Envelope
        XmlElement elementToEncrypt = xml.GetElementsByTagName("Envelope", MyConst.xmlns_soapenv)[1] as XmlElement;

        return elementToEncrypt;
    }
    #endregion
}`
alexnur commented 3 years ago

Кстати, когда пробую дешифровать зашифрованный ответ ФСС (после отправки им зашифрованного запроса, который они прислали мне по почте), то получаю исключение "Плохие данные". Дешифровать пробую как и для спецификации 1.1. Исключение возникает при возврате результата из метода return GostEncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, myKey); Исключение: 'System.Security.Cryptography.CryptographicException' in GostCryptography.dll ("Плохие данные. ")

` private static SymmetricAlgorithm GetDecryptionKey(EncryptedData encryptedData, X509Certificate2 myCert) { IEnumerator encryptedKeyEnumerator = encryptedData.KeyInfo.GetEnumerator(); // Проходим по всем KeyInfo while (encryptedKeyEnumerator.MoveNext()) { // пропускам все что неизвестно. KeyInfoEncryptedKey current = encryptedKeyEnumerator.Current as KeyInfoEncryptedKey; if (current == null) continue; // до первого EncryptedKey EncryptedKey encryptedKey = current.EncryptedKey;

            if (encryptedKey == null)
                continue;
            KeyInfo keyinfo = encryptedKey.KeyInfo;
            // Проходим по всем KeyInfo зашифрования ключа.
            IEnumerator srcKeyEnumerator = keyinfo.GetEnumerator();
            while (srcKeyEnumerator.MoveNext())
            {
                // пропускам все что неизвестно.
                KeyInfoX509Data keyInfoCert = srcKeyEnumerator.Current
                    as KeyInfoX509Data;
                if (keyInfoCert == null)
                    continue;
                var keyContainer = myCert.GetPrivateKeyInfo();
                // Приватный ключ, открытый ключ которого мы отправляли при шифровании запроса
                Gost_R3410_2012_256_AsymmetricAlgorithm dd = new Gost_R3410_2012_256_AsymmetricAlgorithm(ProviderType.CryptoPro_2012_512);

                var privateKey = new Gost_R3410_2012_256_AsymmetricAlgorithm(keyContainer);
                // Приватный ключ, открытый ключ которого мы отправляли при шифровании запроса
                Gost_R3410_2012_256_AsymmetricAlgorithm myKey = privateKey as Gost_R3410_2012_256_AsymmetricAlgorithm;
                if (myKey == null)
                    continue;

                return GostEncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, myKey);
            }
        }
        return null;
    }`
spiridonovav commented 3 years ago

Добрый день.

"Плохие данные.

Такое исключение, насколько я помню, возникает в случае, если в настройках GostCryptography Криптопровайдер не соответствует, указанному в сертификате. Смотрю ваш код. Может общими усилиями разберемся.

spiridonovav commented 3 years ago

Кстати, когда пробую дешифровать зашифрованный ответ ФСС (после отправки им зашифрованного запроса, который они прислали мне по почте), то получаю исключение "Плохие данные"

Мне кажется, что это бесполезно. Так как ответ должен быть зашифрован на ключе, который ФСС получает из расшифрованного подписанного сообщения. Так как зашифрованное сообщение предоставлено ими, то и шифруют ответ они неизвестным вам ключем.

spiridonovav commented 3 years ago

Запрашивал в поддержке тестовый готовый зашифрованный запрос, чтобы исключить остальные проблемы. Прислали зашифрованный запрос. Если я его отправляю на тестовый контур с шифрованием - все хорошо.

Интереснее было бы получить от ФСС и подписанное сообщение и его зашифрованный вариант. В запросе ЭЛН нет никаких закрытых данных. Они вполне могут предоставить эти данные. Можете у них запросить? На всякий случай можете выложить зашифрованный запрос, полученный от ФСС?

spiridonovav commented 3 years ago

byte[] encryptedKey = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificateEncryption.GetPublicKeyAlgorithm());

Не понятно, почему вы шифруете ключ на сертификате страхователя, а не на сертификате ФСС? Вообще не понял, почему у метода EncryptXmlDocument так много параметров-сертифкатов? Нужен ведь сертификат страхователя и сертификат ФСС. Или я ошибаюсь?

alexnur commented 3 years ago

Запрашивал в поддержке тестовый готовый зашифрованный запрос, чтобы исключить остальные проблемы. Прислали зашифрованный запрос. Если я его отправляю на тестовый контур с шифрованием - все хорошо.

Интереснее было бы получить от ФСС и подписанное сообщение и его зашифрованный вариант. В запросе ЭЛН нет никаких закрытых данных. Они вполне могут предоставить эти данные. Можете у них запросить? На всякий случай можете выложить зашифрованный запрос, полученный от ФСС?

Ну да. Они ответ шифровать будут публичным сертификатом страхователя, т.е. в предоставленном ими же зашифрованном запросе указан ихний публичный сертификат (не уполномоченного лица ФСС). В понедельник выложу зашифрованный запрос рабочий. Запросить могу подписанное сообщение и зашифрованное, но нам это мало чем поможет. Ведь у нас получается отправить на сервис с подписанием (который сейчас не доступен). Отвечают они долго. Некоторые письма игнорируют. Вообще такое ощущение что там разные люди отвечают, они не представляются.

alexnur commented 3 years ago

byte[] encryptedKey = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificateEncryption.GetPublicKeyAlgorithm());

Не понятно, почему вы шифруете ключ на сертификате страхователя, а не на сертификате ФСС?

certificateEncryption - Это сертификат ФСС. Форматирование кода тут сломалось вместе с директивами region. Но порядок сохранился для сигнатуры метода: protected override XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, Gost_28147_89_SymmetricAlgorithmBase sharedKey, X509Certificate2 certificateEncryption, X509Certificate2 certificateOpen)

/// Публичный сертификат ФСС. /// Публичный сертификат страхователя.

Вообще не понял, почему у метода EncryptXmlDocument так много параметров-сертифкатов? Нужен ведь сертификат страхователя и сертификат ФСС. Или я ошибаюсь?

Я брал готовый пример, переделывал. С какой целью переделывал - уже не помню. Параметров на самом деле не много

alexnur commented 3 years ago

Выкладываю зашифрованный запрос. Зашифрован тестовым сертификатом ФСС для ЭЛН 2021 года. Параллельно дублирую на файлообменнике: https://dropmefiles.com/jQxmK

Адрес тестового сервиса ЭЛН с шифрованием для страхователя https://docs-test.fss.ru/ws-insurer-crypto-v20/FileOperationsLnService?WSDL

`

MIIIyTCCCHSgAwIBAgIQAdaQCGAJoDAAAAKLA+gAAjAMBggqhQMHAQEDAgUAMIIB2DEYMBYGBSqF A2QBEg0xMDI3NzM5NDQzMjM2MT0wOwYDVQQJDDTQntGA0LvQuNC60L7QsiDQv9C10YDQtdGD0LvQ vtC6LCDQtC4gMywg0LrQvtGA0L8uINCQMRowGAYIKoUDA4EDAQESDDAwNzczNjA1NjY0NzELMAkG A1UEBhMCUlUxGTAXBgNVBAcMENCzLiDQnNC+0YHQutCy0LAxGDAWBgNVBAgMDzc3INCc0L7RgdC6 0LLQsDEdMBsGCSqGSIb3DQEJARYOaW5mby11Y0Bmc3MucnUxZzBlBgNVBAoMXtCk0L7QvdC0INGB 0L7RhtC40LDQu9GM0L3QvtCz0L4g0YHRgtGA0LDRhdC+0LLQsNC90LjRjyDQoNC+0YHRgdC40LnR gdC60L7QuSDQpNC10LTQtdGA0LDRhtC40LgxLjAsBgNVBAsMJdCm0LXQvdGC0YDQsNC70YzQvdGL 0Lkg0LDQv9C/0LDRgNCw0YIxZzBlBgNVBAMMXtCk0L7QvdC0INGB0L7RhtC40LDQu9GM0L3QvtCz 0L4g0YHRgtGA0LDRhdC+0LLQsNC90LjRjyDQoNC+0YHRgdC40LnRgdC60L7QuSDQpNC10LTQtdGA 0LDRhtC40LgwHhcNMjAwOTIxMTExNDAwWhcNMjEwOTIxMTExNDAwWjCCAbExGjAYBggqhQMDgQMB ARIMMDA3NzM2MDU2NjQ3MRgwFgYFKoUDZAESDTEwMjc3Mzk0NDMyMzYxLjAsBgNVBAsMJdCm0LXQ vdGC0YDQsNC70YzQvdGL0Lkg0LDQv9C/0LDRgNCw0YIxZzBlBgNVBAoMXtCk0L7QvdC0INGB0L7R htC40LDQu9GM0L3QvtCz0L4g0YHRgtGA0LDRhdC+0LLQsNC90LjRjyDQoNC+0YHRgdC40LnRgdC6 0L7QuSDQpNC10LTQtdGA0LDRhtC40LgxNTAzBgNVBAkMLNCe0YDQu9C40LrQvtCyINC/0LXRgNC1 0YPQu9C+0LosINC00L7QvCAzINCQMRkwFwYDVQQHDBDQsy4g0JzQvtGB0LrQstCwMRgwFgYDVQQI DA83NyDQnNC+0YHQutCy0LAxCzAJBgNVBAYTAlJVMWcwZQYDVQQDDF7QpNC+0L3QtCDRgdC+0YbQ uNCw0LvRjNC90L7Qs9C+INGB0YLRgNCw0YXQvtCy0LDQvdC40Y8g0KDQvtGB0YHQuNC50YHQutC+ 0Lkg0KTQtdC00LXRgNCw0YbQuNC4MGYwHwYIKoUDBwEBAQEwEwYHKoUDAgIkAAYIKoUDBwEBAgID QwAEQPvJJ0+TWO6eZmUfseZRd6PJ3y++tKoA5WPBNI6wzkWnGndCGd6pqSzh7QW3nthnxvaT57w/ q9h8HiLOWFTY2YmBCQAwM0U4MDAwMqOCBCcwggQjMA4GA1UdDwEB/wQEAwID2DAdBgNVHSUEFjAU BggrBgEFBQcDAgYIKwYBBQUHAwQwJwYDVR0gBCAwHjAIBgYqhQNkcQEwCAYGKoUDZHECMAgGBiqF A2RxAzAyBgUqhQNkbwQpDCfQmtGA0LjQv9GC0L7Qn9GA0L4gQ1NQINCy0LXRgNGB0LjRjyA0LjAw ggHLBgUqhQNkcASCAcAwggG8DIGZ0KHRgNC10LTRgdGC0LLQviDQutGA0LjQv9GC0L7Qs9GA0LDR hNC40YfQtdGB0LrQvtC5INC30LDRidC40YLRiyDQuNC90YTQvtGA0LzQsNGG0LjQuCAo0KHQmtCX 0JgpICJWaVBOZXQgQ1NQIDQuMiIgKNCy0LDRgNC40LDQvdGCINC40YHQv9C+0LvQvdC10L3QuNGP IDMpDFrQn9GA0L7Qs9GA0LDQvNC80L3Ri9C5INC60L7QvNC/0LvQtdC60YEgIlZpUE5ldCDQo9C0 0L7RgdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YAgNCIMXNCX0LDQutC70Y7Rh9C10L3Q uNC1INC+INGB0L7QvtGC0LLQtdGC0YHRgtCy0LjQuCDihJYgMTQ5LzMvMi8yLTIwNTIg0L7RgiAy OS4wMS4yMDE0INCz0L7QtNCwDGTQodC10YDRgtC40YTQuNC60LDRgiDRgdC+0L7RgtCy0LXRgtGB 0YLQstC40Y8g4oSWINCh0KQvMTI4LTI5MzIg0L7RgiAxMCDQsNCy0LPRg9GB0YLQsCAyMDE2INCz 0L7QtNCwMAwGA1UdEwEB/wQCMAAwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2Zzcy5ydS91Yy9H VUNfRlNTX1JGXzIwMjAuY3JsMIIBYAYDVR0jBIIBVzCCAVOAFD2o7bwXrstz2cPo0cin9ryscFZm oYIBLKSCASgwggEkMR4wHAYJKoZIhvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJV MRgwFgYDVQQIDA83NyDQnNC+0YHQutCy0LAxGTAXBgNVBAcMENCzLiDQnNC+0YHQutCy0LAxLjAs BgNVBAkMJdGD0LvQuNGG0LAg0KLQstC10YDRgdC60LDRjywg0LTQvtC8IDcxLDAqBgNVBAoMI9Cc 0LjQvdC60L7QvNGB0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3 MDExGjAYBggqhQMDgQMBARIMMDA3NzEwNDc0Mzc1MSwwKgYDVQQDDCPQnNC40L3QutC+0LzRgdCy 0Y/Qt9GMINCg0L7RgdGB0LjQuIILAKhAVEAAAAAAA58wHQYDVR0OBBYEFBGLbUHNNZEst5g5AfDd 9w6rG2H5MAwGCCqFAwcBAQMCBQADQQDVak5Yshj5IiR0tMqBmPfvVF3SMB/sw6k8qnRwubcePmPF X+VU7vbTLYeSDT82mUC4kXios9LQDpThFlpQrbIn MIGpMCgEIPMiLrXgZaMlkSsom/LuHvGTMezcCbDx5/oCFKQvFB7QBAQ/qlDpoH0GCSqFAwcBAgUB AaBmMB8GCCqFAwcBAQEBMBMGByqFAwICJAAGCCqFAwcBAQICA0MABEC1Lt6OvjR8dvdFVHYf2fjP cT4xRAibFz9QReBwTrX4pjj1e6P3i0aUqGVkg4eYzSkyo9GQ5SN2xqOHwebzhgTsBAjTAf307w2I Jg==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`
alexnur commented 3 years ago

На просьбу прислать тестовый запрос подписанный и зашифрованный получил следующий ответ: "Кажется, что это бессмысленно, т.к. расшифровать запрос в обратную сторону все равно не получится. Обратите внимание, в спецификации страхователя 2.0 описаны шаги по шифрованию запроса. Также, если вы для работы своего ПО используете библиотеку шифрования GostCryptography, то она была переписана, прежняя версия не может корректно работать с сервисом 2.0."

У меня была GostCryptography версии 2.0.7, с которой работала спецификация 1.1. В репозитории есть версия 2.0.8. Установил ее. Изменений никаких - ФСС по-прежнему не может расшифровать мой запрос. Запросы по спецификации 1.1 без проблем работают в том числе и с версией 2.0.7. В АРМ ФСС используется GostCryptography вообще версии 2.0.2. Ее я тоже пробовал подключать к проекту. Изменений никаких. Удивительно другое - согласно ответу ФСС требуется более новая версия, мол со старой работать не будет. А сами используют 2.0.2. В общем, вопрос открыт.

AlexMAS commented 3 years ago

Большие переделки произошли с релизом 2.0, потом были правки мелких багов и косметические дополнения. :)

spiridonovav commented 3 years ago

Также, если вы для работы своего ПО используете библиотеку шифрования GostCryptography, то она была переписана, прежняя версия не может корректно работать с сервисом 2.0."

Очень интересно! А что они такого могли сделать, что:

  1. Шифрование стало "несовместимым" с сервисом 1.1
  2. Спецификация на сервис 2.0 (в разделе шифрования) практически не отличается от спецификации 1.1.

Уважаемый @AlexMAS, вы не могли бы прокомментировать эти новые данные?

Ссылка на спецификацию сервиса 2.0 : https://cabinets-test.fss.ru/%D0%A1%D0%BF%D0%B5%D1%86%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F%D0%AD%D0%9B%D0%9D%D0%A1%D1%82%D1%80%D0%B0%D1%85%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_v_2_0_20210112.docx

spiridonovav commented 3 years ago

В АРМ ФСС используется GostCryptography вообще версии 2.0.2. Ее я тоже пробовал подключать к проекту. Изменений никаких. Удивительно другое - согласно ответу ФСС требуется более новая версия, мол со старой работать не будет. А сами используют 2.0.2. В общем, вопрос открыт.

В АРМ ФСС использует фактически свой вариант GostCryptography. У них в ней свои классы, интерфейсы. Скорее всего у них не заморачиваются с изменением ее версии. В любом случае, у них своя библиотека и сравнивать ее версию с версией открытой библиотеки бесполезно.

AlexMAS commented 3 years ago

Да, скорей всего, у них свой fork, что усложняет ситуацию. Возможно, у них на это были свои причины.

spiridonovav commented 3 years ago

Да, скорей всего, у них свой fork, что усложняет ситуацию. Возможно, у них на это были свои причины.

Но ведь в спецификации должны быть отражены ВСЕ требования? Вы не могли бы предположить, что они могли изменить в сервисе, чтобы перестало расшифровываться сообщение. Вот требования из спецификации сервиса 2.0:

5.1. Этапы шифрования сообщения

  1. Создание случайного сессионного ключа. При работе с ключами на алгоритме ГОСТ 2012 следует инициализировать генератор параметрами шифрования TK26Z (предоставляется провайдером). Алгоритм шифрования GOST28147.
  2. Зашифрование сессионного ключа. 2.1. Создание шифратора для зашифрования ключа. Применяется алгоритм трансформации "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001". Cоздается эфемерный ключ, который согласуется с открытым ключом получателя, и формируется ключ согласования (на котором будет зашифрован сессионный ключ); 2.2. Создание блока KeyInfo с сертификатом; 2.3. Шифрование сессионного ключа происходит с помощью указанного асимметричного ключа (ГОСТ Р 34.10). Cессионный ключ используется для шифрования данных и в свою очередь так же шифруется. CALG_DH_GR3410_12_256_EPHEM - идентификатор алгоритма обмена ключей по Диффи-Хеллману на базе закрытого ключа эфемерной пары. Открытый ключ получается по ГОСТ Р 34.10 2012 (256 бит). CALG_DH_GR3410_12_512_EPHEM - идентификатор алгоритма обмена ключей по Диффи-Хеллману на базе закрытого ключа эфемерной пары. Открытый ключ получается по ГОСТ Р 34.10 2012 (512 бит).
  3. В блоке в подписанном запросе добавляется блок , который содержит публичный сертификат пользователя в формате x509v3 (кодировке base64).
  4. Зашифрование документа. 4.1. Создание шифратора в режиме зашифрования. Применяется алгоритм "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gost28147". Возможные параметры шифратора GostJCE/CBC/ISO10126Padding; 4.2. Добавление зашифрованного сессионного ключа, полученного ранее (добавление блока KeyInfo; 4.3. Зашифрование документа на сессионном ключе.
spiridonovav commented 3 years ago

Выкладываю зашифрованный запрос. Зашифрован тестовым сертификатом ФСС для ЭЛН 2021 года. Параллельно дублирую на файлообменнике: https://dropmefiles.com/jQxmK

Это файл, который вам прислали из ФСС? Или сформированный вами? Хотелось бы посмотреть пример зашифрованного сообщения, которое вам прислали из ФСС.

alexnur commented 3 years ago

Это файл, который вам прислали из ФСС? Или сформированный вами? Хотелось бы посмотреть пример зашифрованного сообщения, которое вам прислали из ФСС.

Это файл подписанного зашифрованного запроса страхователя к тестовому сервису ФСС. Пример прислали из ФСС. Запрос рабочий.

spiridonovav commented 3 years ago

Подставил зашифрованный ключ и зашифрованные данные из примера ФСС в свой запрос. Сервис нормально вернул ответ, который я, естественно, не смог расшифровать. Значит структура сообщения у меня верная. Обратил внимание, что зашифрованный мной ключ имеет размер в BASE64 228 символов, а в примере ФСС 232 символа. Это о чем-то нам может сказать?

spiridonovav commented 3 years ago

На мой вопрос:

Спасибо за ответ:

Ошибка с шифрованием происходит потому, что был изменен порядок формирования зашифрованного >сообщения, изменения описаны в спецификации. Если >вы для >работы своего ПО используете библиотеку шифрования GostCryptography, то она была переписана, прежняя версия не может корректно >работать с сервисом 2.0.*

Я исхожу из фактов: 1. С сервисом 1.1 наша программа работала без ошибок 2. Изменения, в части подписания/шифрования в спецификации сервиса 2.0, сводятся к: а) добавление сертификата отправителя в подписанное сообщение перед шифрованием б) в зашифрованное сообщение вместо сертификата отправителя (сервис 1.1) прикладывается сертификат ФСС. Все остальные буквы спецификации сервиса 2.0, в части подписания/шифрования, не отличаются от спецификации 1.1 и, следовательно, уже реализованы в программе, которая работает с сервисом 1.1. С другой стороны, вы утверждаете, что GostCryptography в исходном виде не может работать с сервисом 2.0. Это наводит на мысль, что спецификация сервиса 2.0 не полная и не содержит какие-то существенные технические нюансы, которые необходимо реализовать для работы с сервисом 2.0. Огромная просьба от всего человечества: опубликуйте эти технические детали, которые не позволяют GostCryptography работать с сервисом 2.0. Или опубликуйте исходный код GostCryptography из АРМ ФСС или еще как-то, но дайте информацию, а уж мы разберемся как доработать наше ПО. Надеюсь на вашу помощь в этом вопросе, так как обратиться больше просто не к кому!

Был получен ответ:

Добрый день! Заявка PPO2021-18913 Вопросы приведенные в заявке находятся вне компетенции технической поддержки. Техническая поддержка отвечает за работоспособность сервисов ЭЛН и поддерживаемых приложений, дает консультации по бизнес-процессам и применяемым форматно-логическим контролям, итп. Техническая поддержка не дает консультаций и решений по разработке сторонних приложений. Стандарты и алгоритмы, используемые при работе сервиса ЭЛН, являются открытыми и перечислены в спецификациях

Т.е. помощи от ФСС больше ждать бессмысленно.

alexnur commented 3 years ago

Может попытаться декомпилировать АРМ ФСС и подсмотреть использование ими форкнутой GostCryptography? Чем это лучше сделать? И возможно ли?

alexnur commented 3 years ago

Саппорт конечно интересный у них... Для кого тогда эти спецификации? Я пока не знаю ни одного человека, который бы смог по этой спецификации 2.0 получить ЭЛН. Читал только сообщения о том, что отправка медицинской организацией в ФСС по 2.0 - работает. Даже тут человек написал. Похоже на то, что государственный фонд нас принуждает для собственных разработок делать заказ в "правильных" (неправильные просто не знают как зашифровать) фирмах по разработке ПО. Мне кажется это специально сделано - для формальности, мол мы все описали в спецификации. То, что не все (а может быть и все) не могут по этой спецификации правильно зашифровать - говорит либо о непрофессионализме автора спецификации, неумении донести до разработчиков информации, либо об умысле. Мое мнение, никому не навязываю. Но примеры бы в спецификации не помешали. Достаточно было бы на каком-нибудь одном, пусть и экзотическом, языке. Как вариант еще можно рассмотреть - написать письмо в Минздрав с просьбой о содействии (вменяемости в обязанности) в получении консультаций из саппорта ФСС. Письмо подписать руководителями наших предприятий. Чем больше будет подписей (или писем) - тем лучше, понятен будет масштаб.

kosmitster commented 3 years ago

Может попытаться декомпилировать АРМ ФСС и подсмотреть использование ими форкнутой GostCryptography? Чем это лучше сделать? И возможно ли?

@alexnur, Приветствую! Поделюсь своим опытом в этом вопросе. Качал АРМ ФСС, по умолчанию ставится в папку c:\FssTools. После установки в папке c:\FssTools находится файл GostCryptography.dll Этот файл, работает в связке с АРМ ФСС как COM объект. Вот из этого GostCryptography.dll с помощью jetbrains dotPeek (он бесплатен), вызовом Export to Project, создал csproj. Далее через класс CryproServer01 можно посмотреть методы которые вызывает АРМ ФСС. Я делал следующем образом. После того как у меня были исходники, я подключился дебагером в Visual Studio к библиотеке GostCryptography.dll, и вызывая методы класса CryproServer01 из АРМ ФСС, дебажил что и как происходит в библиотеки GostCryptography.dll

spiridonovav commented 3 years ago

Может попытаться декомпилировать АРМ ФСС и подсмотреть использование ими форкнутой GostCryptography? Чем это лучше сделать? И возможно ли?

@alexnur, Приветствую! Поделюсь своим опытом в этом вопросе. Качал АРМ ФСС, по умолчанию ставится в папку c:\FssTools. После установки в папке c:\FssTools находится файл GostCryptography.dll Этот файл, работает в связке с АРМ ФСС как COM объект. Вот из этого GostCryptography.dll с помощью jetbrains dotPeek (он бесплатен), вызовом Export to Project, создал csproj. Далее через класс CryproServer01 можно посмотреть методы которые вызывает АРМ ФСС. Я делал следующем образом. После того как у меня были исходники, я подключился дебагером в Visual Studio к библиотеке GostCryptography.dll, и вызывая методы класса CryproServer01 из АРМ ФСС, дебажил что и как происходит в библиотеки GostCryptography.dll

Спасибо за подсказку. У меня тоже этот вариант как самый перспективный остался. Разгребу текущие работы и сделаю еще один заход на эту проблему.

IrinaPushkarev commented 3 years ago

Добрый день, тоже занимаюсь интеграцией с ФСС в части ЭЛН. После перехода на версию ЭЛН 2.0 интеграция перестала работать. При запросе ЭЛН возвращается ответ: Не удалось расшифровать сообщение. Возможно сообщение зашифровано на ключе отличном от ключа уполномоченного лица ФСС. Проверьте правильность и актуальность ключа уполномоченного лица ФСС. Проверили подписание, шифрование по документации. Спецификации соответствует, но сообщение в ФСС не распознается. Предполагаю, что изменения произошли в части шифрования, но не описаны в документации. Прошу написать, у кого проблема решилась.

alexnur commented 3 years ago

Сейчас даже по спецификации 1.1 есть проблема с 22 марта, которая до сих пор не решена. Поле LPU_EMPL_FLAG (Признак места работы (со слов гражданина)) при получении любого ЭЛН имеет значение NULL. Согласно спецификации 1.1 это поле обязательное. Обнаружили случайно работники при использовании самописного ПО. Проверьте у себя, проблема у нас никак не проявлялась до того момента пока не заметил один из работников. Почему не было ошибки (возможно она есть у всех, но не проявляется)? Я у себя это поле тоже пометил как обязательное. Проблема в том, что ФСС судя по всему использовал поле типа BIT (NOT NULL). Согласно спецификации 2.0 это поле вообще упразднили. Судя по всему они придумали некий шлюз, который выдает в т.ч. ЭЛН полученные из МО, по спецификации 2.0 через спецификацию 1.1 (но это - только моя догадка), и вот там косяк. Одно время тоже так было, но потом исправили. Так вот, из-за того что у них 0 является идентификатором (это значение поля, но если оно ссылается на справочник, это - идентификатор), а это поле NULL'ом быть не может, но каким образом будет проинициализирована эта переменная (в C#)? Правильно, 0. Получается, что сейчас, начиная с 22 марта мы в своих разработках инициализируем и затем отправляем обратно в ФСС неверное значение этого поля. Например, все работники, указавшие через МО "основной признак места работы", после получения такого ЭЛН страхователем, получают значение этого поля как "по совместительству". Может быть это и не страшно, однако ФСС потом сверяет данные отправленные страхователю, с теми данными, которые от от страхователя получает. И будет несостыковка, т.к. это поле страхователь править не имеет права. Непонятно что потом будет с таким больничным. Проверьте у себя. Писал не один раз в саппорт. Проблему признают, но начиная с 22 марта просят дождаться решения, которого до сих пор нет. Проверьте у себя значение поля LPU_EMPL_FLAG - какое получаете из ФСС и каким оно инициализируется в ваших программах (NULL != 0)

IrinaPushkarev commented 3 years ago

alexnur, спасибо. Но у меня вопрос по части шифрования. Напишите, пожалуйста, какие изменения произошли в шифровании ЭЛН 2.0. Потому что у нас запрос ЭЛН не проходит, дальше будем разбираться с новым XML.

alexnur commented 3 years ago

IrinaPushkarev, еще ни у кого не получилось отправить через спецификацию 2.0.

IrinaPushkarev commented 3 years ago

alexnur, но интеграция в Контур, 1С работает. А получение ЭЛН по спецификации 1.1 у вас работает?

alexnur commented 3 years ago

IrinaPushkarev сам XML с ФСС я получаю. Но с пустым полем LPU_EMPL_FLAG. Возможно что Контур и 1С получают ЭЛН по спецификации 2.0. Я получаю по 1.1 (уже больше года), и в 1.1 - проблема с 22 марта.

alexnur commented 3 years ago

Ответила поддержка про поле LPU_EMPL_FLAG = NULL при получении ЭЛН 2.0 по спецификации 1.1.: "Исправлено, при запросе данных ЭЛН, оформленных по версии 2.0, страхователем с сервиса в версии 1.1, в поле LPU_EMPL_FLAG по умолчанию подставляется значение 1, т.е основное место работы.*"

sviasn commented 3 years ago

Тут написали, что удалось получить ответ по спецификации 2.0. У кого-нибудь получилось?

alexnur commented 3 years ago

Завтра попробую, если время будет. Если что с понедельника. Пишите, у кого получилось :)

kostyanich33 commented 3 years ago

Кому-нибудь удается отправить реестр БЛ в ФСС через prParseReestrFile ? Запрос больничного через getPrivateLNData сделали достаточно быстро, работает, а вот отправка ругается на отсутствие всех подписей и "В сертификате организации отсутствует ОГРН (ОГРНИП), а также отсутствует уполномоченный представитель с таким сертификатом ЭП. Необходимо использовать сертификат с ОГРН (ОГРНИП) либо оформить доверенность для уполномоченного представителя." При этом 1.1 работало без проблем, учитывая доработки под получение больничного для версии 2.0, которые работают, сложно представить где ошибка. При этом ошибки одинаковые у всех клиентов, вряд ли там реальные проблемы с сертификатом. При этом на порчу/удаление блоков Security с подписями вообще 0 реакции, ругается как раньше без изменений. Запрос сделал 1 в 1 под пример в спецификации, но что забавно ответ мы получаем точно такой же как и в спецификации - нет подписей )) и дополнительно про сертификат страхователя.

alexnur commented 3 years ago

Не получилось у меня получить ЭЛН по 2.0, учитывая информацию из https://www.cryptopro.ru/forum2/default.aspx?g=posts&m=124012#post124012 (исходник на Delphi). Ничего не понял.

2kostyanich33: Можете выложить код получения ЭЛН по спецификации 2.0 (getPrivateLNData)? Тут у присутствующих пока не получилось то, что получилось у вас.

alexnur commented 3 years ago

Декомпилировал форкнутую версию GostCryptography от ФСС. Решил кое какие мелочи, с которыми не справился декомпилятор (jetBrains DotPeek), добился того, чтобы проект собрался. В выходную директорию bin/debug, где расположена скомпилированная версия dll (файлы GostCryptography.dll, GostCryptography.pdb) скопировал рабочую настроенную версию "АРМ ФСС для расчетов" за исключением библиотеки GostCryptography.dll, т.к. цель - иметь точки останова от декомпилированной. Указал в получившемся проекте в DEBUG => Start External Program путь к arm_fss.exe, расположенному в каталоге со скомпилированной GostCryptography.dll. Поставил точки остановка в классе CryptoServer01 на методах signSOAPMessage, encryptSOAPMessage, decryptSOAPMessage. Запустил проект в студии, запустился внешний процесс arm_fss.exe. Пробую получить ЭЛН - срабатывают точки останова, все видно, что происходит. ЭЛН получаю. Создаю новый проект, добавляю туда ссылку на GostCryptography от ФСС, вызываю методы. Все подписывается, шифруется, однако из ФСС приходит ответ: Удаленный сервер возвратил ошибку: (500) Внутренняя ошибка сервера.. soap:VersionMismatch"http://www.w3.org/2001/04/xmlenc#", the namespace on the "EncryptedData" element, is not a valid SOAP version.

Даже подготовил болванку для XML, один в один как в АРМ ФСС, проверяю теги после подписи и шифрования - все верно. Наверное, я не на то url отправляю. Я отправляю на: request = (System.Net.HttpWebRequest)WebRequest.Create("https://docs.fss.ru/ws-insurer-crypto-v20/FileOperationsLnService?WSDL"); Также добавляю заголовок request.Headers.Add("SOAPAction", "\"http://www.fss.ru/integration/ws/eln/ins/getPrivateLNData/v01\""); и получаю описанную ошибку. В общем, прогресс есть, ФСС уже может расшифровать запрос. Правда решение начал не с той стороны, но мне не принципиально, пусть будет через форкнутую GostCryptoGraphy от ФСС. Посмотрел URL для АРМ ФСС в ProxySet.ini:

[FSS_WEB_SERVICE]
;WSDLLocation=https://docs-test.fss.ru/ws-insurer-crypto-v11/FileOperationsLnPort?WSDL
;WSDLLocation=https://docs.fss.ru/ws-insurer-crypto-v11/FileOperationsLnPort?WSDL
ServiceURL=

[FSS_WEB_SERVICE_20]
;WSDLLocation=https://docs-test.fss.ru/ws-insurer-crypto-v20/FileOperationsLnService?WSDL 
WSDLLocation=https://docs.fss.ru/ws-insurer-crypto-v20/FileOperationsLnService?WSDL

С этими настройками АРМ ФСС работает. Если убрать последнюю строку, то уже не работает, правда ссылается на жестко вшитую в код ссылку (не присутствует в файле ProxySet.ini)

Есть какие-то мысли у кого?

alexnur commented 3 years ago

Все ок. Необходимо было обернуть результат, полученный после работы метода encryptSOAPMessage в новое сообщение SOAP. Я почему-то считал, что на выходе должно быть SOAP-сообщение, готовое для отправки в ФСС. Нужно еще решить вопрос с передачей серийных номеров сертификатов в GostCryptography от ФСС: сейчас сертификаты находятся только если серийные номера константы. Если через переменные - то не находит. Пробовал править декомпилированную библиотеку от ФСС по части поиска сертификатов - сертификаты находились, однако в дальнейшем при шифровании была ошибка "не найден набор ключей". В общем над этим подумаю еще, но самый главный вопрос решен - я получаю ЭЛН 2.0 из своего ПО (пусть через DLL от ФСС - этот момент не критичен. Может быть так даже правильно - при очередных изменениях спецификации и шифрования, достаточно будет скачать новую версию АРМ ФСС с пропатченной библиотекой).

alexnur commented 3 years ago

Как использовать.

  1. Качаем "АРМ подготовки расчетов для ФСС": https://lk.fss.ru/eln.html (прямая ссылка: http://fss.ru/ru/fund/download/55818/index.shtml)

  2. Устанавливаем это ПО. После установки идем по пути установленной программы (C:\FSSRF\ARM_FSS или C:\FSSRF.net\ARM_FSS_NET если сетевая версия). Копируем куда-нибудь библиотеку GostCryptography,dll.

  3. На текущий момент это fork от ФСС mit-версии GostCryptography 2.0.2.0 от 14.11.2019. Размер 205 824 байт.

  4. Добавляем ссылку (Reference) из своего проекта на GostCryptography.dll от ФСС.

  5. Используем следующую болванку для SOAP-сообщения: ` public readonly static string FssQueryTemplate2 = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "

  6. Добавляем данные по ЭЛН: XmlDocument doc = new XmlDocument(); doc.LoadXml(GlobalVariables.FssQueryTemplate2); foreach (XmlElement xe in getPrivateLnDataNode) { if (xe.Name == "regNum") { xe.FirstChild.Value = regNumber; } else if (xe.Name == "lnCode") { xe.FirstChild.Value = dataForFss.LnCode; } else if (xe.Name == "snils") { xe.FirstChild.Value = dataForFss.PensNo; } } doc.PreserveWhitespace = true;

  7. Далее полученный XML используем в классе MyCprypt.

`public class MyCrypt {

region Конструктор. Подписание/шифрование для ФСС по спецификации 2.0.

    /// <summary>
    ///  Подписание/шифрование для ФСС по спецификации 2.0.
    /// </summary>
    /// <param name="cryptoProvider"> Имя криптопровайдера, например "Crypto-Pro CSP 256". </param>
    public MyCrypt(string cryptoProvider)
    {
        _cryptoProvider = cryptoProvider;
    }
    #endregion

    private IInterface01 _interface01 = new CryproServer01();
    private string _cryptoProvider;

    #region Подписание запроса для ФСС по спецификации 2.0.
    /// <summary>
    ///  Подписание запроса для ФСС по спецификации 2.0.
    /// </summary>
    /// <param name="request"> Подписываемое сообщение SOAP. </param>
    /// <param name="signingCertificate"> Серийный номер сертификата страхователя. </param>
    /// <param name="regnumber"> Регистрационный номер страхователя (цифры). </param>
    /// <param name="xPath"> Дополнительная информация. Указывать необязательно. </param>
    public string Sign(
              string request,
              string signingCertificate,
              string regnumber,
              string xPath = "/soapenv:Envelope/soapenv:Body")
    {
        string id = "REGNO_" + regnumber;
        string actor = "http://eln.fss.ru/actor/insurer/" + regnumber;
        string result = _interface01.signSOAPMessage(_cryptoProvider, request,
               signingCertificate, xPath, id, actor);

        return result;
    }
    #endregion

    #region Шифрование запроса для ФСС по спецификации 2.0.
    /// <summary>
    ///  Шифрование для ФСС по спецификации 2.0.
    /// </summary>
    /// <param name="senderCert"> Серийный номер сертификата страхователя. </param>
    /// <param name="recieverCert"> Серийный номер сертификата уполномоченного лица ФСС. </param>
    /// <param name="message"> Cообщение SOAP, которое необходимо зашифровать. </param>
    /// <param name="wrapInNewSoapMessage"> При TRUE (по умолчанию) сообщение после шифрования будет обёрнуто в новое 
    /// SOAP-сообщение. </param>
    public string Encrypt(string senderCert, string recieverCert, string message, bool wrapInNewSoapMessage=true )
    {
        // Серийные номера сертификатов могут содержать невидимые символы.
        // Подробности: https://support.microsoft.com/ru-ru/topic/certificate-thumbprint-displayed-in-mmc-certificate-snap-in-has-extra-invisible-unicode-character-c9e58dcb-f39a-d0a1-f7fc-bcaaa6fe64e4
        // Необходимо избавиться от них при их наличии.
        var rgx = new Regex("[^a-fA-F0-9]");
        senderCert = rgx.Replace(senderCert, string.Empty).ToUpper();
        recieverCert = rgx.Replace(recieverCert, string.Empty).ToUpper();
        string result = _interface01.encryptSOAPMessage(_cryptoProvider, senderCert, recieverCert, message);
        if (wrapInNewSoapMessage)
        {
            result = "<?xml version=\"1.0\"?>" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body>" + result;
            result += "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
        }

        return result;
    }
    #endregion

    #region Дешифрование овтета из ФСС по спецификации 2.0.
    /// <summary>
    ///  Дешифрование овтета из ФСС по спецификации 2.0.
    /// </summary>
    /// <param name="recieverCert"> Серийный номер сертификата страхователя. </param>
    /// <param name="message"> Зашифрованное сообщение SOAP, полученное из ФСС. </param>
    public string Decrypt(string recieverCert, string message)
    {
        string result = _interface01.decryptSOAPMessage(_cryptoProvider, recieverCert, message);

        return result;
    }
    #endregion

}`
denx08 commented 3 years ago

Здравствуйте! Есть опыт взаимодействие с SOAP ЭЛН 2.0 под C#, если есть вопросы пишите, попробую помочь.

wrx888 commented 3 years ago

Всем добрый день, что то совсем уже запутался с этим 2.0 Вроде структура файла вся правильная, шифруется..всё внешне похоже на примеры и до шифрования и после, но ответ всегда один, что не тем ключом. Вижу что 14 дней не обсуждали, каким все таки нужно правильным путем пойти, чтобы победить этот фсс с новой версией?