Веб-сервисы с поддержкой ЭЦП на базе криптографии ГОСТ

Начиная с версии 2008.2, в Caché и в Ensemble встроена поддержка WS-Security, включающая механизмы проверки и формирования электронной подписи SOAP-сообщений. На текущий момент имеется “out of the box” поддержка ЭЦП на базе крипто алгоритмов семейства RSA.

К системам, создаваемым для российских заказчиков, зачастую предъявляется требование применения сертифицированных СКЗИ, использующих крипто алгоритмы ГОСТ. Далее описан один из подходов к разработке веб-сервисов Caché, защищенных ЭЦП на базе ГОСТ’овской криптографии.

В качестве сертифицированного СКЗИ, будем использовать продукт КриптоПро JCP, представляющий собой набор Java библиотек, в которых реализован алгоритм подписи – ГОСТ Р 34.10-2001, а также алгоритм хэширования ГОСТ Р 34.11-94.

Установка КриптоПро JCP на Windows

Прежде всего, на сервер системы установите Java Runtime Environment (JRE) версии не ниже 1.6.

Загрузите дистрибутив КриптоПро JCP с сайта производителя, распакуйте его в папку на сервере и запустите скрипт установки install.bat. Скрипт находится в папке lib дистрибутива. При его запуске необходимо указать путь к JRE:

install.bat "C:\Program Files\Java\jdk1.6.0_20\jre"

В случае если имеется лицензия, при запуске скрипта также указывается серийный номер и название компании:

install.bat "C:\Program Files\Java\jdk1.6.0_20\jre" XXXXX-XXXXX-XXXXX-XXXXX-XXXXX "Your Company"

Под Windows 7 скрипт установки необходимо запускать с правами администратора. После завершения работы скрипта, убедитесь в том, что в папке jre\lib\ext появились следующие библиотеки:

asn1rt.jar JCP.jar JCPRevCheck.jar JCP_ASN.jar
AsnLite.jar JCPinst.jar JCPRevTools.jar JCryptoP.jar
forms_rt.jar JCPRequest.jar JCPxml.jar

Дополнительные библиотеки Java

Нам понадобится библиотека iscjcp.jar (исходники здесь), в которой содержится ряд вспомогательных классов для работы с JCP из Caché. Кроме этого, потребуются три open source библиотеки – Commons Logging, Santuario (aka XML Security) и WSS4J. Их использование регулируется лицензией Apache Software License 2.0.

Загрузите архив jars.zip с четырьмя перечисленными библиотеками и распакуйте его в папку jre\lib\ext.

В случае использования Windows 7, необходимо выдать полномочия группе «Все» на чтение и выполнение всех библиотек в папке jre\lib\ext.

Настройка и запуск Java Gateway, создание проекций классов

Чтобы стало возможным вызывать Java-классы из Caché/Ensemble, необходимо настроить и запустить Java Gateway, а также создать проекции используемых Java-классов.

Добавим новую запись в таблицу настроек Java Gateway в области %SYS:

insert into %Net_Remote.ObjectGateway(Name, Type, Server, Port, JavaHome) values ('JCPGate', '1', '127.0.0.1', '55555', 'C:\Program Files\Java\jdk1.6.0_20\jre')

Здесь в поле Name указано значение “JCPGate” – это имя нового Java Gateway. В поле JavaHome необходимо указать путь к JRE, для которой была произведена установка JCP. В поле Port указывается TCP-порт, используемый для общения с этим Java Gateway из Caché.

Теперь можно запустить новый Java Gateway, выполнив в терминале Caché следующую команду:

write ##class(%Net.Remote.Service).StartGateway("JCPGate")

Чтобы остановить его, вызовите метод StopGateway:

write ##class(%Net.Remote.Service).StopGateway("JCPGate")

Запускать/останавливать Java Gateway можно из любой области.

Перейдем в область, где ведется разработка веб-сервисов, и создадим проекцию для Java-класса isc.jcp.JcpFacade, выполнив в терминале Caché следующую команду:

do ##class(%Net.Remote.Java.JavaGateway).%ExpressImport("isc.jcp.JcpFacade", "55555")

Здесь 55555 – это номер TCP-порта, который используется для общения с Java Gateway. Этот порт был указан нами ранее при добавлении записи в таблицу %Net_Remote.ObjectGateway.

Проверка ЭЦП во входящих SOAP-сообщениях

Загрузите и распакуйте архив iscjcp-cos-sources.zip с исходным кодом классов smev.JcpUtils и smev.JcpSignature. Импортируйте класс smev.JcpUtils в Caché с помощью Studio, предварительно перейдя в область, где ведется разработка веб-сервисов. Откройте импортированный класс в Studio и отредактируйте значения параметров JAVAGATEWAYPORT и JAVAGATEWAYSERVER, указав соответственно TCP-порт и IP-адрес используемого Java Gateway. Скомпилируйте класс.

Теперь, чтобы добавить в существующий веб-сервис проверку ЭЦП, достаточно внести в класс веб-сервиса следующий метод:

Method OnPreSOAP(mode As %String, action As %String, request)
{
  #dim stream As %Stream.Object = request

  if '$isObject(stream)
  {
    // на случай MIME attachments
    #dim index As %Integer = %request.NextMimeData("")
    set stream = $select(index="":"", 1:%request.GetMimeData(index))
  }

  if $isObject(stream)
  {
  #dim fault As %SOAP.Fault = ##class(smev.JcpUtils).verifySignatureOnPreSoap(stream)
    if $isObject(fault) set ..SoapFault = fault
  }
}

Это работает на версиях Caché/Ensemble, начиная с 2009.1. Ниже приведен пример веб-сервиса, который осуществляет проверку подписи всех входящих SOAP-сообщений.

Class test.TestService Extends %SOAP.WebService
{
  Parameter SERVICENAME = "TestService";

  Parameter NAMESPACE = "http://test/wsdl";

  Method echo(request As %String) As %String [ ProcedureBlock = 1, SoapAction = "urn:echo", SoapBindingStyle = document, SoapBodyUse = literal, WebMethod ]
  {
     quit request
  }

  Method OnPreSOAP(mode As %String, action As %String, request)
  {
    #dim stream As %Stream.Object = request

    if '$isObject(stream)
    {
      // на случай MIME attachments
      #dim index As %Integer = %request.NextMimeData("")
      set stream = $select(index="":"", 1:%request.GetMimeData(index))
    }

    if $isObject(stream)
    {
      #dim fault As %SOAP.Fault = ##class(smev.JcpUtils).verifySignatureOnPreSoap(stream)
      if $isObject(fault) set ..SoapFault = fault
    }
  }
}

Формирование ЭЦП для исходящих SOAP-сообщений веб-сервиса

Далее рассмотрим случай, когда все ответы веб-сервиса должны быть подписаны ЭЦП организации. В такой ситуации на сервере системы размещается хранилище, содержащее секретный ключ, который используется при формировании подписи. Кроме того, должен быть доступен сертификат, соответствующий этому ключу. В библиотеке iscjcp.jar реализована работа с хранилищем типа “FloppyStore”. Поэтому, для формирования ЭЦП нам потребуется виртуальная дискета с хранилищем ключей.

Размещение секретного ключа и сертификата на виртуальной дискете на сервере системы

Чтобы создать такую дискету, выполните следующие действия:

  1. Установите драйвер, имитирующий FDD привод, например, ImDisk.
  2. Из панели управления Windows запустите программу настройки “ImDisk Virtual Disk Driver” и настройте диск с параметрами:
    • Drive letter: A,
    • Size of virtual disk: 1 Megabyte,
    • Device type: Floppy.
  3. Отформатируйте виртуальную дискету, задав файловую систему FAT.
  4. Распакуйте содержимое архива FDD.zip на диск A:\.

В результате описанных манипуляций на диске A:\ сервера имеем хранилище ключей, содержащее тестовый секретный ключ. Файл A:\SelfSigned.cer представляет собой тестовый сертификат, соответствующий секретному ключу.

Вы можете самостоятельно генерировать ключи и сертификаты с помощью КриптоПро JCP. Эти процедуры описаны в документации продукта.

Формирование ЭЦП

Загруженный ранее архив iscjcp-cos-sources.zip с исходным кодом Caché Object Script содержал класс smev.JcpSignature. Импортируйте этот класс в Caché с помощью Studio.

Откройте класс smev.JcpUtils в Studio и отредактируйте значение параметра CERTFILENAME, указав полный путь к файлу сертификата – “A:\SelfSigned.cer”. Этот сертификат соответствует секретному ключу, который будет использоваться при формировании ЭЦП. Скомпилируйте класс.

Теперь, чтобы добавить в метод веб-сервиса функционал по формированию ЭЦП для возвращаемых сообщений, необходимо вставить следующую строку в код этого метода:

do ..SecurityOut.AddElement(##class(smev.JcpSignature).%New())

Это работает на версиях Caché/Ensemble, начиная с 2009.1, по 2011.1 включительно. Ниже приведен пример веб-сервиса, где в метод echo() добавлено подписывание ответа.

Class test.TestService Extends %SOAP.WebService
{
  Parameter SERVICENAME = "TestService";

  Parameter NAMESPACE = "http://test/wsdl";

  Method echo(request As %String) As %String [ ProcedureBlock = 1, SoapAction = "urn:echo", SoapBindingStyle = document, SoapBodyUse = literal, WebMethod ]
  {
     do ..SecurityOut.AddElement(##class(smev.JcpSignature).%New())
     quit request
  }

  Method OnPreSOAP(mode As %String, action As %String, request)
  {
    #dim stream As %Stream.Object = request

    if '$isObject(stream)
    {
      // на случай MIME attachments
      #dim index As %Integer = %request.NextMimeData("")
      set stream = $select(index="":"", 1:%request.GetMimeData(index))
    }

    if $isObject(stream)
    {
      #dim fault As %SOAP.Fault = ##class(smev.JcpUtils).verifySignatureOnPreSoap(stream)
      if $isObject(fault) set ..SoapFault = fault
    }
  }
}

Тестирование веб-сервиса

Чтобы протестировать проверку/формирование ЭЦП веб-сервисом test.TestService, исходный код которого приведен выше, выполним следующие действия.

  1. При помощи Studio создадим класс test.TestService в той же области, куда были импортированы классы smev.*. Исходный код нового класса скопируем из вышеприведенного листинга.
  2. С помощью Блокнота создадим файл C:\Temp\input.xml, содержащий тело входящего SOAP-сообщения для сервиса test.TestService:
     
    <SOAP-ENV:Body wsu:Id="id1"
            xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <s0:echo xmlns:s0="http://test/wsdl">
        <s0:request>Здравствуй, мир!</s0:request>
      </s0:echo>
    </SOAP-ENV:Body>

    Файл необходимо сохранить в кодировке UTF-8. Обратите внимание на атрибут wsu:Id корневого элемента Body.

    Готовый файл input.xml имеется в архиве xmls.zip.

  3. Запустим в терминале Caché метод signFile() класса smev.JcpUtils:

     
    write ##class(smev.JcpUtils).signFile("id1", "C:\Temp\input.xml", "C:\Temp\output.xml")

    Убедимся в том, что в результате работы метода был создан файл C:\Temp\output.xml, содержащий подписанное SOAP-сообщение (Envelope): в заголовке (Header) находится ЭЦП в формате WS-Security, а тело (Body) представляет собой XML-документ, взятый из файла input.xml.

    Готовый файл output.xml имеется в архиве xmls.zip.

  4. Направим полученное SOAP-сообщение с ЭЦП на вход сервиса test.TestService. Для этого выполним в терминале Caché следующие команды (при необходимости, замените порт веб-сервера – “57772” на правильный, а также область “user” в предпоследней команде):
     
    set httprequest = ##class(%Net.HttpRequest).%New()
    set httprequest.Server = "localhost"
    set httprequest.Port = "57772"
    set httprequest.WriteRawMode = 1
    set httprequest.ContentType = "text/xml"
    do httprequest.SetHeader("SOAPAction","urn:echo")
    set fileStream = ##class(%Library.FileBinaryStream).%New()
    set fileStream.Filename = "C:\Temp\output.xml"
    do httprequest.EntityBody.CopyFrom(fileStream)
    do httprequest.Post("/csp/user/test.TestService.cls")
    do httprequest.HttpResponse.OutputToDevice()
     
    Если успешно прошла проверка ЭЦП входящего сообщения, а затем и формирование ЭЦП исходящего, то в окне терминала появится ответ веб-сервиса примерно такого вида:
     
    HTTP/1.1 200 OK
    CACHE-CONTROL: no-cache
    CONNECTION: close
    CONTENT-LENGTH: 2352
    CONTENT-TYPE: text/xml; charset=UTF-8
    DATE: Thu, 01 Dec 2011 20:08:40 GMT
    EXPIRES: Thu, 29 Oct 1998 17:04:19 GMT
    PRAGMA: no-cache
    SERVER: Apache
    SET-COOKIE: CSPSESSIONID-SP-57774-UP-csp-user-=0000000100001odLLhtp000000igxIuSVnd12z6BtrSIFFJA–; path=/csp/user/;
     
    <?xml version="1.0" encoding="UTF-8" ?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV=’http://schemas.xmlsoap.org/soap/envelope/’ xmlns:xsi=’http://www.w3.org/2001/XMLSchema-instance’ xmlns:s=’http://www.w3.org/2001/XMLSchema’ xmlns:wsse=’http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd’ xmlns:wsu=’http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd’>
    <SOAP-ENV:Header>
    <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><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="#Body-B290AFEC-9812-49E4-9177-6D617D30622C">
    <ds:Transforms>
    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    </ds:Transforms>
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/>
    <ds:DigestValue>vs42sfoxCX8naSV2NnBSoIoCvUb1ydvvyNnp5XC7nKQ=</ds:DigestValue>
    </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>
    ES4aVXFSkHr1cnXUcdZYJTPTa+e5//ASQRYhrRMy46pWSwRW93VxgrW+GhATD2xwK3l+8T1Dfsi2
    beVfrkQS0g==
    </ds:SignatureValue>
    <ds:KeyInfo>
    <ds:X509Data>
    <ds:X509Certificate>
    MIIB9TCCAaSgAwIBAgIIRdAY3dqebKUwCAYGKoUDAgIEMCkxJzAlBgNVBAMeHgB0AC4AZQAuAG0A
    LgBwAEAAbQBhAGkAbAAuAHIAdTAeFw0xMTExMjkxMzQwMTFaFw0xMjExMjkxMzQwMTFaMCkxJzAl
    BgNVBAMeHgB0AC4AZQAuAG0ALgBwAEAAbQBhAGkAbAAuAHIAdTBjMBwGBiqFAwICEzASBgcqhQMC
    AiMBBgcqhQMCAh4BA0MABECebxtl5EDpwaWKy2MeJQ7v+NCiIRHiXBeqaqJnNi5AS4aW+14FKKHH
    Llu7jjggB06d+/4U29OtDbjfIkPqRUcio4GtMIGqMB0GA1UdDgQWBBTz0qujqn+CC0O9L1aSv39a
    ga3EhDALBgNVHQ8EBAMCAcYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDwYDVR0TBAgwBgEB/wIBATBW
    BgNVHQEETzBNgBTz0qujqn+CC0O9L1aSv39aga3EhKErMCkxJzAlBgNVBAMeHgB0AC4AZQAuAG0A
    LgBwAEAAbQBhAGkAbAAuAHIAdYIIRdAY3dqebKUwCAYGKoUDAgIEA0EANUalM3ag0xYJ7MqzmCzh
    w8ejPqUds37UXKadbyqogZ2yJBMbhWUCsQFyZZZzfc6gXQbRThBTAftfdXxjW8Yusg==
    </ds:X509Certificate>
    </ds:X509Data>
    </ds:KeyInfo>
    </ds:Signature>
    </Security> </SOAP-ENV:Header>
    <SOAP-ENV:Body wsu:Id="Body-B290AFEC-9812-49E4-9177-6D617D30622C"><echoResponse xmlns="http://test/wsdl"><echoResult>Здравствуй, мир!</echoResult></echoResponse></SOAP-ENV:Body>
    </SOAP-ENV:Envelope>

Веб-сервисы с поддержкой ЭЦП на базе криптографии ГОСТ: 5 комментариев

  1. Как сказано выше, с помощью класса smev.JcpSignature из архива iscjcp-cos-sources.zip формируется ЭЦП в версиях Caché/Ensemble с 2009.1 по 2011.1 включительно. Недавно вышел релиз 2012.1. Архив iscjcp-cos-sources2012.zip содержит доработанный класс smev.JcpSignature, пригодный для использования на новой версии.

  2. В случае если веб-сервис унаследован от класса EnsLib.SOAP.Service (системный класс Ensemble), то для правильной работы системы необходимо добавить вызов кода предка в начало метода OnPreSOAP():

    do ##super(mode, action, request)

  3. Уведомление: Cache и Ensemble | Commandus blog

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *