PHP CURL issues "unable to get local issuer certificate" error

1

I am trying to get data from an API using the PHP CURL extension but it is not working. The same code on another server is working.

Here it works:

Buthereitnolongerworks:

Thecodeis:

<?php$con=curl_init();$url="https://api.moloni.com/v1/companies/getOne/?access_token=123456";
    $my_values = array('company_id' => 0);

    curl_setopt($con, CURLOPT_URL, $url);
    curl_setopt($con, CURLOPT_POST, true);
    curl_setopt($con, CURLOPT_POSTFIELDS, http_build_query($my_values));
    curl_setopt($con, CURLOPT_HEADER, false);
    curl_setopt($con, CURLOPT_RETURNTRANSFER, true);

    $res_curl = curl_exec($con);
    curl_close($con);

    $res_txt = json_decode($res_curl, true);
    if(!isset($res_txt['error'])){
        echo 'Result: '.print_r($res_txt,true).'';
    }else{
        echo 'Erro: '.print_r($res_txt,true).'';
    }

    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);

?>
    
asked by anonymous 01.02.2016 / 12:42

1 answer

4

For the error reported in the comments, the problem is in SSL.

There are alternatives, not very recommended to solve (or check if this is the problem).

Verification:

Add:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt($ch, CURLOPT_CAINFO, 'local/crt.crt');

Explanation:

The CURLOPT_SSL_VERIFYHOST will check if the host that is connecting is the same as the certificate was received, simple as well. When it is 2 it will then check the Subject Alternate Name and Common Name field in the certificate. Keep it off ( 0 / false ) will ignore the check.

The CURLOPT_SSL_VERIFYPEER is a bit more complex. When enabled it will verify that the certificate that was received (by whom you connected) was issued (having a CA trusted). In this case cURL will compare the certificates whether or not it was issued by someone who trusts, this is recommended. Keeping off ( 0 ) will prevent you from verifying the authenticity of the certificate, leaving you exposed even for self-signed certificates and for man-in-the-middle attacks. The CURLOPT_CAINFO is just used when CURLOPT_SSL_VERIFYPEER .

CURLOPT_CAINFO allows you to choose a location where the certificate is located on your server.

Try to turn everything off (as in the section above) and see if the error persists, continuing the certificate is not the problem.

Remember to NEVER USE THIS IN PRODUCTION, you are turning off SSL verification, if you use this, you should know that this is extremely vulnerable and unreliable!

Solution:

You have two options:

1. Generic (Multiple Certification Authority):

Log in to link download the latest CA Bundle available for download.

OR

2. Specific Certificate (Specific Certification Authority):

You can choose to just rely on a single SSL issuer, rather than several as above. That way it takes who issued the certificate, so trust it.

Use Mozilla Firefox for this!

  • Enter the desired site (example: link ).
  • Click the green lock (next to the site URL).
  • Click the arrow next to " Conexão segura " and click " Mais informações ".
  • Click " Ver certificado ".
  • This will show all information, but you want to save a specific one.

  • Click the " Detalhes " tab.
  • There is a hierarchy, you need to save what is specific to the domain.

    In my case there are:

      

    GlobalSign Root CA      

        

    GlobalSign Domain Validation CA - SHA256 - G2

             
          

    .openssl.org

        
      

    Select the first ( GlobalSign Root CA ) and click " Exportar ".

    Use:

    Suppose the following structure:

    seuphp.php (que usa o cURL)
    seucertifiado.crt (que acabou de salvar)
    

    Modify the code for:

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_CAINFO, 'caminho/para/seucertificado.crt');
    

    This will solve the problem.

      

    The paths must be absolute!

    Is this safe? Yes, it could be more.

    If you want to trust only a specific certificate, for much more security, you should use CURLOPT_PINNEDPUBLICKEY , for this you need to have CURL in version higher than 7.39.0 and have PHP in version 7.0.7 < in> even because using an obsolete version of PHP and wanting security is kind of incoherent.

    For this you get the certificate of the website (if you do not have it):

    openssl s_client -servername www.example.com -connect www.example.com:443 < /dev/null | sed -n "/-----BEGIN/,/-----END/p" > /caminho/para/arquivo.pem
    

    Then add this to CURL :

    curl_setopt($ch, CURLOPT_PINNEDPUBLICKEY, 'caminho/para/seucertificado.pem');
    

    This will check if the certificate informed to the CURL is the same certificate that CURL obtained when connecting, otherwise the connection will be canceled.

    This is very useful if you are communicating with a payment website, such as PayPal, MoIP, PagSeguro, MercadoPago, this makes it even more difficult for a certificate to be falsified using a trusted CA. / p>     

    01.02.2016 / 17:00