5

I'm trying to post data to a payment gateway API. It required post data in xml format. I have the following code:

<?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. Output of var_dump($content); is empty ''.
  2. Output of var_dump(curl_getinfo($ch));.

    array (size=26)
    'url' => string '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' => string '' (length=0)
    'primary_ip' => string '91.227.244.57' (length=13)
    'certinfo' =>
    array (size=0)
    empty
    'primary_port' => int 8444
    'local_ip' => string '192.168.100.64' (length=14)
    'local_port' => int 53456

  3. Ouput of var_dump(curl_errno($ch)); : int 60

  4. Output of var_dump(curl_error($ch)); :

    string 'SSL certificate problem: unable to get local issuer certificate' (length=63) It seems like the API is returning no data as seen on curl_getinfo(). Please help me, I have seen almost every solution suggested in communities.

I have edited my php.ini file to give the path to the certificate downloaded from curl website. But this did not work as well.

Halil Özgür
  • 15,731
  • 6
  • 49
  • 56
P S
  • 435
  • 1
  • 8
  • 26
  • The error means that /etc/apache2/ssl/m4/mydomain.com.crt doesn't contain the CA certificates that signed HTTPS server certificate. You need to add them. – Oleg Jan 12 '18 at 15:30
  • @Oleg Sorry, I did not get it. I got this certificate from my payment gateway. Could you be more elaborative. Thank you for your response. – P S Jan 12 '18 at 15:32

2 Answers2

2

When you connect to the server to establish secure connection you as a client get server's certificate in the beginning of the conversation with it. This certificate and its private key are used to establish the secure connection. You client wants to ensure that the server's certificate is trusted and is not created by some man-in-the middle attacker. So your client need to have the CA certificate that signed the server certificate. The error above means that the client tried to find server's certificate issuer (or one of the issuers in the chain) and didn't find. The place it tries to find it is in the specified /etc/apache2/ssl/m4/mydomain.com.crt file. You have two options: either add CA certificate to the file or to disable server certificate verification (not secure) by setting CURLOPT_SSL_VERIFYPEER to false.

Oleg
  • 726
  • 5
  • 11
  • I have put my .csr .crt and .key files in `/etc/apache2/ssl/m4/`. What else is needed and what to do? – P S Jan 13 '18 at 16:30
  • You need to put the CA certificate that signed the server certificate to /etc/apache2/ssl/m4/mydomain.com.crt file, not to /etc/apache2/ssl/m4/ directory. – Oleg Jan 16 '18 at 14:28
  • Next step: you specified CURLOPT_SSL_VERIFYHOST=2. From curl doc: When CURLOPT_SSL_VERIFYHOST is 2, that certificate must indicate that the server is the server to which you meant to connect, or the connection fails. Simply put, it means it has to have the same name in the certificate as is in the URL you operate against. Does your certificate fit this above? – Oleg Jan 16 '18 at 16:25
  • suggest trying to remove options one by one loosing security until it starts working, then you will know which check fails – Oleg Jan 16 '18 at 16:36
  • Okay I'll do that. – P S Jan 16 '18 at 16:38
0

I got support from my API providers who pointed something missing in my approach. For their gateway I needed to load the private key, public key and password that protects these keys in curl request. The solution is as follows:

/*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);

Now every thing works as expected.

P S
  • 435
  • 1
  • 8
  • 26