Проблема с сертификатом SSL не может получить сертификат локального эмитента

Я пытаюсь опубликовать данные в API платежного шлюза. Требовались почтовые данные в формате xml. У меня есть следующий код:

<?php
$requestUrl = 'https://api.given.bypg'; //$block->getPaymentUrl();

$amount = 100; // $block->totalOrderAmount()*100; 

$approveUrl = $block->approveUrl();
$cancelUrl =  $block->cancelUrl();
$declineUrl = $block->declineUrl();


$merchant = 'mydomain.com'; 
//$amount = '100'; // in cents. 1$ = 100cents. 
$currency = '840'; // for dollar
$description = 'Happy customers is what we make.';
$merchantId = 'Nobel106513';
?>

<?php
echo $requestUrl;
$xml_data = '<TKKPG>
<Request>
<Operation>CreateOrder</Operation>
<Language>EN</Language>
<Order>
<OrderType>Purchase</OrderType>
<Merchant>'.$merchantId.'</Merchant>
<Amount>'.$amount.'</Amount>
<Currency>'.$currency.'</Currency>
<Description>'.$description.'</Description>
<ApproveURL>'.$approveUrl.'</ApproveURL>
<CancelURL>'.$cancelUrl.'</CancelURL>
<DeclineURL>'.$declineUrl.'</DeclineURL>
</Order>
</Request>
</TKKPG>';

$ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $requestUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60000);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data);//My post data
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($ch, CURLOPT_CAPATH, "/etc/apache2/ssl/m4/mydomain.com.crt");
        curl_setopt($ch, CURLOPT_CAINFO, "/etc/apache2/ssl/m4/mydomain.com.crt");
        curl_setopt($ch, CURLOPT_CERTINFO, 1);

        $headers = [];
        array_push($headers, 'Content-Type: text/xml;charset=UTF-8');
        //array_push($headers, 'SoapAction: *');
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $content = trim(curl_exec($ch));
        var_dump($content);
        var_dump(curl_getinfo($ch));
        var_dump(curl_errno($ch));
        var_dump(curl_error($ch));
        curl_close($ch);
  1. Выход var_dump($content); пуст ''.
  2. Выход var_dump(curl_getinfo($ch));.

    массив (размер = 26)
    'url' => строка 'https://api.given.bypg'
    'content_type' => null
    'http_code' => int 0
    'header_size' => int 0
    'request_size' => int 0
    'filetime' => int -1
    'ssl_verify_result' => int 1
    'redirect_count' => int 0
    'total_time' => float 0.488533
    'namelookup_time' => float 0.028558
    'connect_time' => float 0.256858
    'pretransfer_time' => float 0
    'size_upload' => float 0
    'size_download' => float 0
    'speed_download' => float 0
    'speed_upload' => float 0
    'download_content_length' => float -1
    'upload_content_length' => float -1
    'starttransfer_time' => float 0
    'redirect_time' => float 0
    'redirect_url' => строка '' (длина=0)
    'primary_ip' => строка '91.227.244.57' (длина=13)
    'certinfo' =>
    массив (размер=0)
    пустой
    'primary_port' => int 8444
    'local_ip' => строка '192.168.100.64' (длина = 14)
    'local_port' => int 53456

  3. Выход var_dump(curl_errno($ch)); : int 60

  4. Вывод var_dump(curl_error($ch)); :

    string 'Проблема с сертификатом SSL: невозможно получить сертификат локального эмитента' (длина = 63) Похоже, что API не возвращает данные, как показано в curl_getinfo(). Пожалуйста, помогите мне, я видел почти все решения, предложенные в сообществах.

Я отредактировал свой файл php.ini, чтобы указать путь к сертификату, загруженному с веб-сайта curl. Но и это не сработало.


person Purushotam Sangroula    schedule 11.01.2018    source источник
comment
Ошибка означает, что /etc/apache2/ssl/m4/mydomain.com.crt не содержит сертификатов ЦС, которые подписали сертификат HTTPS-сервера. Вам нужно добавить их.   -  person Oleg    schedule 12.01.2018
comment
@Олег Извините, я не понял. Я получил этот сертификат от моего платежного шлюза. Не могли бы вы быть более подробным. Благодарю за ваш ответ.   -  person Purushotam Sangroula    schedule 12.01.2018


Ответы (2)


При подключении к серверу для установки защищенного соединения вы как клиент получаете сертификат сервера в начале разговора с ним. Этот сертификат и его закрытый ключ используются для установки безопасного соединения. Ваш клиент хочет убедиться, что сертификат сервера является доверенным и не создан каким-то посредником. Таким образом, ваш клиент должен иметь сертификат CA, который подписал сертификат сервера. Ошибка выше означает, что клиент пытался найти эмитента сертификата сервера (или одного из эмитентов в цепочке) и не нашел. Место, которое он пытается найти, находится в указанном /etc/apache2/ssl/m4/mydomain.com.crt файле. У вас есть два варианта: либо добавить сертификат ЦС в файл, либо отключить проверку сертификата сервера (небезопасную), установив для параметра CURLOPT_SSL_VERIFYPEER значение false.

person Oleg    schedule 12.01.2018
comment
Я поместил свои файлы .csr .crt и .key в /etc/apache2/ssl/m4/. Что еще нужно и что делать? - person Purushotam Sangroula; 13.01.2018
comment
Вам нужно поместить сертификат CA, который подписал сертификат сервера, в файл /etc/apache2/ssl/m4/mydomain.com.crt, а не в каталог /etc/apache2/ssl/m4/. - person Oleg; 16.01.2018
comment
Следующий шаг: вы указали CURLOPT_SSL_VERIFYHOST=2. Из документа curl: когда CURLOPT_SSL_VERIFYHOST имеет значение 2, этот сертификат должен указывать, что сервер является сервером, к которому вы хотели подключиться, иначе соединение не будет установлено. Проще говоря, это означает, что в сертификате должно быть то же имя, что и в URL-адресе, с которым вы работаете. Ваш сертификат соответствует вышеизложенному? - person Oleg; 16.01.2018
comment
предложите попробовать удалить параметры один за другим, теряя безопасность, пока он не начнет работать, тогда вы будете знать, какая проверка не удалась - person Oleg; 16.01.2018
comment
Хорошо, я сделаю это. - person Purushotam Sangroula; 16.01.2018

Я получил поддержку от своих поставщиков API, которые указали на то, что в моем подходе чего-то не хватает. Для их шлюза мне нужно было загрузить закрытый ключ, открытый ключ и пароль, который защищает эти ключи в запросе curl. Решение выглядит следующим образом:

/*ssl crts*/
$twpg_cert_file = "/etc/apache2/ssl/m4/mydomain.com.crt";
$twpg_key_file = "/etc/apache2/ssl/m4/mydomain.com.key";
$twpg_key_password = '';
/*ssl crts*/
$ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $requestUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60000);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data);//My post data
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($ch, CURLOPT_SSLCERT,  $twpg_cert_file);
        curl_setopt($ch, CURLOPT_SSLKEY, $twpg_key_file);
        curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $twpg_key_password);
        curl_setopt($ch, CURLOPT_CERTINFO, 1);
        $headers = [];
        array_push($headers, 'Content-Type: text/xml;charset=UTF-8');
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $content = trim(curl_exec($ch));
        curl_close($ch);

Теперь все работает как положено.

person Purushotam Sangroula    schedule 21.01.2018