Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Взаимодействие php-soap на linux с авторизацией по сертификатам с применением алгорифмов ГОСТ

Anna | 31.05.2014 | нет комментариев

С криптографией я сталкивался ранее, доводилось разворачивать удостоверяющий центр на КриптоПро в свое время, так что всеобщие представления о том что такое закрытые и открытые ключи и сертификаты у меня имелось, но вот о том как все это работает в Linux представления специального не было.
Встала задача обеспечить взаимодействие со службами РосМинздрава, а именно — с федеральным регистром медработников по протоколу SOAP. Со стороны заказчика система на CentOS и работающими службами на PHP, со стороны сервера — SOAP-сервис с авторизацией по сертификатам с применением ГОСТ алгорифмов. В наличии была флешка с закрытым ключом, сформированным удостоверяющим центром РосМинздрава и сертификат этого ключа.
Позже обзора обстановки по применению ГОСТ алгорифмов шифрования в мире Linux выяснено что за последние годы тут есть отменное движение вперед, но все таки не вовсе все отлично. Выходит, для того Дабы принудить растяжение php-soap прозрачно понимать алгорифмы ГОСТ, а также применять сертификаты и ключи выданные РосМинздравом необходимо сделать следующее:

1. Обновить в дистрибутиве библиотеку OpenSSL до версии не ниже 1.0.1с и настроить поддержку ГОСТ.
2. Преобразовать выданный ключ и сертификат в формат, внятный OpenSSL. Проверить работу OpenSSL.
3. Подправить растяжение OpenSSL в PHP и перекомпилировать сам PHP. Протестировать работу SOAP на PHP.

Выходит, приступим. Данные дистрибутива, установленного php и библиотеки openssl:

# lsb_release -a
LSB Version:	:base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID:	CentOS
Description:	CentOS release 6.4 (Final)
Release:	6.4
Codename:	Final

# yum list installed | grep php
php.x86_64             5.3.3-22.el6     @base                                   
php-cli.x86_64         5.3.3-22.el6     @base                                   
php-common.x86_64      5.3.3-22.el6     @base                                   
php-dba.x86_64         5.3.3-22.el6     @base                                   
php-devel.x86_64       5.3.3-22.el6     @base                                   
php-imap.x86_64        5.3.3-22.el6     @base                                   
php-ldap.x86_64        5.3.3-22.el6     @base                                   
php-lessphp.noarch     0.3.9-1.el6      @epel                                   
php-mbstring.x86_64    5.3.3-22.el6     @base                                   
php-mcrypt.x86_64      5.3.3-1.el6      @epel                                   
php-odbc.x86_64        5.3.3-22.el6     @base                                   
php-pdo.x86_64         5.3.3-22.el6     @base                                   
php-pear.noarch        1:1.9.4-4.el6    @base                                   
php-pgsql.x86_64       5.3.3-22.el6     @base                                   
php-process.x86_64     5.3.3-22.el6     @base                                   
php-shout.x86_64       0.9.2-6.el6      @epel                                   
php-soap.x86_64        5.3.3-22.el6     @base                                   
php-xml.x86_64         5.3.3-22.el6     @base                                   
php-xmlrpc.x86_64      5.3.3-22.el6     @base 

# yum list installed | grep openssl
openssl.x86_64         1.0.0-27.el6_4.2 @updates                                
openssl-devel.x86_64   1.0.0-27.el6_4.2 @updates  

 

Обновление библиотеки OpenSSL

Способ собирать «из исходников» и загрязнять систему — не наш способ. Следственно наилучший вариант — обнаружить готовый пакет, и я его обнаружил в репозитории axivo:

# rpm -ivh --nosignature http://rpm.axivo.com/redhat/axivo-release-6-1.noarch.rpm
# yum --enablerepo=axivo update openssl

Проверяем установленную версию OpenSSL:

# openssl version
OpenSSL 1.0.1e 11 Feb 2013

Дальше нужно настроить библиотеку на применение алгорифмов ГОСТ, для этого редактируем файл настроек тот, что лежит по адресу /etc/pki/tls/openssl.cnf, добавив в самое предисловие файла строку:

openssl_conf = openssl_def

и в самый конец файла:

[openssl_def]
engines=engine_section

[engine_section]
gost=gost_section

[gost_section]
engine_id=gost
default_algorithms=ALL
CRYPT_PARAMS=id-Gost28147-89-CryptoPro-A-ParamSet

Позже внесенных изменений проверяем, видит ли OpenSSL алгорифмы ГОСТ:

#openssl ciphers | tr ":" "n" | grep GOST
GOST2001-GOST89-GOST89
GOST94-GOST89-GOST89

 

Преобразуем выданный ключ и сертификат в формат, внятный OpenSSL

Для этого нам потребуется Windows машина с установленным CryptoPRO CSP 3.6. Я его слил с сайта разработчика (там дается демонстрационный режим режим на 3 месяца).
Первое что делаем — экспортируем ключевой контейнер в реестр средствами КриптоПро. Для этого открываем КриптоПро из панели управления Windows. Вставляем наш ключевой носитель в компьютер. Для обыкновенной флешки убеждаемся, что у нассреди считывателей на вкладке «Оборудование» есть «Все съемные диски» и «Реестр». Если у вас не обыкновенная флешка а что-то типа РуТокен либо Etoken либо иной носитель — нужно присутствие его драйверов и библиотеки для применения в КриптоПро (Его должно быть видно в разделе «Настроить Считыватели» на той же вкладке).

Дальше переходим на вкладку «Сервис» и нажимаем «Копировать», нажимаем «Обзор» и выбираем среди списка свой ключевой контейнер. Если его там внезапно не находим — то возвращаемся к предыдущему параграфу и все проверяем. Дальше вводим осмысленное имя нового ключевого контейнера, нажимаем «Готово» и в качестве носителя в появившемся окне выбираем «Реестр». Новейший пароль на контейнер не ставим.
Сейчас нам необходимо установить сертификат в новейший контейнер. На вкладке «Сервис» в КриптоПро нажимаем кнопку «Установить индивидуальный Сертификат», указываем файл с нашим сертификатом, нажимаем «Дальше», выбираем только что сделанный нами контейнер и не забываем галочку «Установить сертификат в контейнер».
Для того Дабы экспортировать данный сертификат в формате PKSC#12 совместно с закрытым ключом — нам потребуется сторонняя утилита. Которую дозволено либо приобрести тут либо обнаружить на просторах интернета по имени p12fromgostcsp. Запускаем данную утилиту, выбираем наш сертификат, пароль оставляем пустым и сберегаем его в файл mycert.p12.
Копируем полученный сертификат на linux-машину. Проверяем, что в сертификате у нас есть оба ключа — закрытый и открытый:

# openssl pkcs12 -in mycert.p12 -nodes

На запрос пароля легко нажимаем Enter. И глядим присутствие строк BEGIN CERTIFICATE и BEGIN PRIVATE KEY. Если строки есть то все в порядке. Преобразуем полученный сертификат в формат PEM:

# openssl pkcs12 -in mycert.p12 -out mycert.pem -nodes -clcerts

Если вам необходима не только авторизация по клиентскому сертификату, но и также проверка валидности самого сервера — вам потребуется корневой сертификат удостоверяющего центра. Его дозволено легко через Windows открыть и сберечь в формате DER в кодировке X.509 (Со вкладки «Состав» при просмотре сертификата), так как закрытого ключа он не содержит. После этого преобразовать его в PEM формат через OpenSSL.

# openssl x509 -inform DER -in cacert.cer -outform PEM -out cacert.pem

Где cacert.cer — имя начального файла с корневым сертификатом. Проверить коннект с сервером с применением сертификатов дозволено через OpenSSL командой:

# openssl s_client -connect service.rosminzdrav.ru:443 -CAfile cacert.pem -cert mycert.pem

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

New, TLSv1/SSLv3, Cipher is GOST2001-GOST89-GOST89
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : GOST2001-GOST89-GOST89
    Session-ID: ***
    Session-ID-ctx: 
    Master-Key: ***
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1375875984
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

 

Правка и перекомпиляция PHP

Основная задача заключается в том, что для того Дабы OpenSSL использовала файл конфигурации по умолчанию (именно там у нас прописаны настройки для алгорифмов ГОСТ) перед ее применением нужно вызвать функцию OPENSSL_config(NULL). В растяжении PHP OpenSSL этого не сделано, следственно модуль PHP-SOAP при применении SSL-соединения не видит алгорифмов ГОСТ. Кстати, тоже самое касается и других библиотек, скажем curl. Ее тоже необходимо патчить если вы собираетесь с ней трудиться.
Выходит приступим. Для того Дабы нам исправить OpenSSL нужно перекомпилировать каждый PHP, так как в CentOS растяжение OpenSSL сделано не модулем.
Подготавливаем среду для сборки пакетов:

# yum install rpm-build redhat-rpm-config
# mkdir /root/rpmbuild
# cd /root/rpmbuild
# mkdir BUILD RPMS SOURCES SPECS SRPMS
# mkdir RPMS/{i386,i486,i586,i686,noarch,athlon}

Качаем исходники PHP и устанавливаем их:

# wget http://vault.centos.org/6.4/os/Source/SPackages/php-5.3.3-22.el6.src.rpm
# rpm -ivh php-5.3.3-22.el6.src.rpm

Переходим в папку SOURCES и извлекаем php, делаем копию папки с иходниками:

# cd SOURCES
# tar xvjf php-5.3.3.tar.bz2
# cp php-5.3.3 php-5.3.3p -R

Правим файл php-5.3.3p/ext/openssl/openssl.c:
Находим строку SSL_library_init(); (у меня это строка № 985) и прописываем перед ней
OPENSSL_config(NULL);.
Переходим в папку SOURCES и формируем патч:

# diff -uNr php-5.3.3/ php-5.3.3p/ > php-5.3.3-gostfix.patch

В итоге получится файл со дальнейшим содержимым:

diff -uNr php-5.3.3/ext/openssl/openssl.c php-5.3.3p/ext/openssl/openssl.c
--- php-5.3.3/ext/openssl/openssl.c	2010-06-26 20:03:39.000000000  0400
    php-5.3.3p/ext/openssl/openssl.c	2013-08-07 11:32:41.944581280  0400
@@ -981,7  981,7 @@
 	le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
 	le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
 	le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
-
 	OPENSSL_config(NULL);
 	SSL_library_init();
 	OpenSSL_add_all_ciphers();
 	OpenSSL_add_all_digests();

Сейчас необходимо принудить сборщик применять наш патч. Правила сборки описаны в файле SPEC/php.spec. Открываем его и позже строки изложения патчей (у меня это строка начинающаяся на Patch230) вставляем строку с изложением нового патча:

Patch231: php-5.3.3-gostfix.patch

Также прописываем вызов данного патча перед сборкой, для этого ищем строки начинающиеся на %patch и в конце них прописываем

%patch231 -p1

Сберегаем файл. Перед сборкой пакета ставим все зависимости для сборки:

# yum install bzip2-devel db4-devel gmp-devel httpd-devel pam-devel sqlite-devel pcre-devel libedit-devel libtool-ltdl-devel libc-client-devel cyrus-sasl-devel openldap-devel mysql-devel postgresql-devel libxml2-devel net-snmp-devel libxslt-devel libxml2-devel libXpm-devel libpng-devel freetype-devel libtidy-devel aspell-devel recode-devel libicu-devel enchant-devel net-snmp

Дальше приступаем к сборке, из папки rpmbuld запускаем команду:

rpmbuild -ba SPECS/php.spec

Сборка занимает продолжительное время, и в случае если все прошло отлично, в папке RPMS/{Ваша_архитектура} появятся готовые rpm_пакеты.
Для архитектуры x86_64:

# ls RPMS/x86_64/
php-5.3.3-22.el6.x86_64.rpm            
php-devel-5.3.3-22.el6.x86_64.rpm     
php-intl-5.3.3-22.el6.x86_64.rpm      
php-pgsql-5.3.3-22.el6.x86_64.rpm    
php-tidy-5.3.3-22.el6.x86_64.rpm
php-bcmath-5.3.3-22.el6.x86_64.rpm     
php-embedded-5.3.3-22.el6.x86_64.rpm  
php-ldap-5.3.3-22.el6.x86_64.rpm      
php-process-5.3.3-22.el6.x86_64.rpm  
php-xml-5.3.3-22.el6.x86_64.rpm
php-cli-5.3.3-22.el6.x86_64.rpm        
php-enchant-5.3.3-22.el6.x86_64.rpm   
php-mbstring-5.3.3-22.el6.x86_64.rpm  
php-pspell-5.3.3-22.el6.x86_64.rpm   p
hp-xmlrpc-5.3.3-22.el6.x86_64.rpm
php-common-5.3.3-22.el6.x86_64.rpm     
php-fpm-5.3.3-22.el6.x86_64.rpm       
php-mysql-5.3.3-22.el6.x86_64.rpm     
php-recode-5.3.3-22.el6.x86_64.rpm   
php-zts-5.3.3-22.el6.x86_64.rpm
php-dba-5.3.3-22.el6.x86_64.rpm        
php-gd-5.3.3-22.el6.x86_64.rpm        
php-odbc-5.3.3-22.el6.x86_64.rpm     
php-snmp-5.3.3-22.el6.x86_64.rpm
php-debuginfo-5.3.3-22.el6.x86_64.rpm  
php-imap-5.3.3-22.el6.x86_64.rpm      
php-pdo-5.3.3-22.el6.x86_64.rpm       
php-soap-5.3.3-22.el6.x86_64.rpm

Сейчас можем установить все это «благо» поверх теснее установленного php с заменой:

rpm -Uvh --replacepkgs --replacefiles RPMS/x86_64/*

Дальше проверяем работу php-soap. Для примера дозволено применять такой код (пример для обслуживания «Федеральный регистр медработников»):

<?php
class GetEmployees
{
public $ogrn;
}
    $cert="/mycert.pem";
 //Сертификат
    $wsdl="https://service.rosminzdrav.ru/MedStaffIntegration/MedStaff.svc?wsdl"; //Адрес wdsl обслуживания
    $loc = "https://service.rosminzdrav.ru/MedStaffIntegration/medstaff.svc/basic";
 //Адрес точки доступа
    $sp = new SoapClient($wsdl,array(
            'local_cert' => $cert,
             'trace' => 1,
            'exceptions' => 1,
            'soap_version' => SOAP_1_1,
            'location' =>$loc,
            ));
    $emp = new GetEmployees;
    $emp->ogrn = '1022303554570';
    try{
         $data = $sp->GetEmployees($emp);
         print_r($data);
        }  catch (SoapFault $e) { 
        echo "<h2>Exception Error!</h2>"; 
        echo $sp->__getLastRequest();
        echo get_class($e);
        echo $e->getMessage(); 
}

Если все прошло удачно никаких ошибок не возникнет и PHP-SOAP без задач заработает.
Дальше если нужно дозволено также подправить библиотеку curl, сделать проверку сертификата сервера и вообще все операции которые возможны для SSL-соединений вплотную до поднятия своего веб сервера с авторизацией по сертификатам с алгорифмами ГОСТ.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB