20

I need some assistance rewriting this PHP curl code that uses *.pem (CA cert), Client cert and private key in one file:

curl_setopt($curl, CURLOPT_URL, $this->url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSLCERT, $this->keystore);
curl_setopt($curl, CURLOPT_CAINFO, $this->keystore);
curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $this->keystorepassword);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

So it could use CA certificate, Client Certificate and Private Key in separate files.

As in this command-line example:

curl -d "var1=value1&var2=value2&..." -G -v --key key.pem --cacert ca.pem --cert client.pem:xxxxxx https://www.somesite.com/page

jww
  • 97,681
  • 90
  • 411
  • 885
somerandomusername
  • 1,993
  • 4
  • 23
  • 55

2 Answers2

43

Here is a PHP script with a literal translation of your command line call:

<?php

  $data = "var1=value1&var2=value2&...";
  $url = "https://www.somesite.com/page";


  $keyFile = "key.pem";
  $caFile = "ca.pem";
  $certFile = "client.pem";
  $certPass = "xxxxxx";

  // Initialise cURL
  $ch = curl_init($actualUrl);

  // The -d option is equivalent to CURLOPT_POSTFIELDS. But...
  // PHP's libcurl interface does not implement the -G flag - instead you would
  // append $data to $url like this:
  $actualUrl = $url.'?'.$data;
  curl_setopt($ch, CURLOPT_URL, $actualUrl);

  // The -v flag only makes sense at the command line, but it can be enabled
  // with CURLOPT_VERBOSE - in this case the information will be written to
  // STDERR, or the file specified by CURLOPT_STDERR. I will ignore this for
  // now, but if you would like a demonstration let me know.

  // The --key option - If your key file has a password, you will need to set
  // this with CURLOPT_SSLKEYPASSWD
  curl_setopt($ch, CURLOPT_SSLKEY, $keyFile);

  // The --cacert option
  curl_setopt($ch, CURLOPT_CAINFO, $caFile);

  // The --cert option
  curl_setopt($ch, CURLOPT_SSLCERT, $certFile);
  curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $certPass);

  /*
    Now we should get an identical request to the one created by your command
    line string, let's have a look at some of the other options you set...
  */

  // CURLOPT_HEADER is disabled by default, there's no need for this unless you
  // enabled it earlier
  //curl_setopt($ch, CURLOPT_HEADER, 0);

  // Your command line string forces a GET request with the -G option, are you
  // trying to POST or GET?
  //curl_setopt($ch, CURLOPT_POST, true);

  // We don't need body data with a GET request
  //curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

  // Since we've gone to all the trouble of supplying CS information, we might
  // as well validate it!
  //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
TomS
  • 635
  • 5
  • 9
DaveRandom
  • 87,921
  • 11
  • 154
  • 174
  • Thank you very much, I'l try this as soon as I get home. – somerandomusername Jul 04 '12 at 12:29
  • Ahaha! It took me a couple of hours to find this well annotated example in order to understand that `CURLOPT_CAINFO` is equivalent to the `--cacert` flag. I was dumbly using `CURLOPT_SSLCERT` — seems friggin obvious now. Kudos, @DaveRandom. – Mark Fox Mar 04 '14 at 23:06
  • 19
    I eventually got home. Glad it helped you two. – somerandomusername Mar 05 '14 at 15:47
  • 1
    The $curl in ```curl_setopt($curl, CURLOPT_URL, $actualUrl);``` should also be $ch, shouldn't it? – andi79h Oct 04 '18 at 10:56
  • Where are you putting your *.crt and *.key file? It is not safe to load them from your current dir? and if you are loading from anywhere else, then 600 permission doesn't allow your server (www-data) to read this file and if you allow 640, then there would be an error that too much permission... – Khuram Aug 09 '21 at 09:05
  • Whats the difference between these `.pem` files?. `$keyFile = "key.pem";` `$caFile = "ca.pem";` `$certFile = "client.pem";` in this curl page `https://curl.se/docs/caextract.html` you can only get the `cacert.pem` what about the `key.pem` and `client.pem`?? any idea??? – ErickBest Aug 19 '21 at 18:26
  • Interestingly, I had to enable verify peer option to make curl actually check the remote server certificate, otherwise it wouldn't care at all about the CA cert. The code above is wrong too, you need to set the option to TRUE. `curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);` – Link14 Jan 07 '22 at 00:14
0

The following code can be used to send a post request with key and cert.

This code is equvalent to the following curl

curl --cert yourkey.pem --key yourcert.key -d 'grant_type=client_credentials&client_id=1&client_secret=2' https://accounts.youraccount.com/auth/oauth/v2/token

 $CURLOPT_URL= "https://accounts.youraccount.com/auth/oauth/v2/token";
 $CURLOPT_POSTFIELDS= "grant_type=client_credential&client_id=1&client_secret=2";
    $clientCert = dirname(__FILE__) . '/certificates/yourkey.key';
    $clientKey = dirname(__FILE__) . "/certificates/yourcert.pem";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,  $CURLOPT_URL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $CURLOPT_POSTFIELDS);
    curl_setopt($ch, CURLOPT_SSLKEY, $clientCert);
    curl_setopt($ch, CURLOPT_SSLCERT, $clientKey);
    $headers = array();
    $headers[] = 'Content-Type: application/x-www-form-urlencoded';
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_SSLCERT, $certFile);
    curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);

    $result = curl_exec($ch);
    if (curl_errno($ch)) {
        echo 'Error:' . curl_error($ch);
    }
    print_r($result);
    curl_close($ch);
    exit;
jewelhuq
  • 1,210
  • 15
  • 19