22

I've a CERT and private key files. I'm using cUrl and PHP to connect to another service. At the moment, I've cert and key in files and it works perfectly fine with following code:

$pemfile = "cert.pem";
$keyfile = "private_key.key";
$url = "someTestUrl";
$requestXml = "requestData";

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $url); 
curl_setopt($ch, CURLOPT_VERBOSE, 1); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); 
curl_setopt($ch, CURLOPT_FAILONERROR, 1); 
curl_setopt($ch, CURLOPT_SSLCERT, $pemfile); 
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM'); 
curl_setopt($ch, CURLOPT_SSLKEY, $keyfile); 
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestXml);
$ret = curl_exec($ch);

My question is: Can I pass cert and key as strings rather passing them as files? I tried simply passing contents of respective files as strings like this:

$pemfile = "-----BEGIN CERTIFICATE-----CERTDATAASSTRING-----END CERTIFICATE-----";
$keyfile = "-----BEGIN RSA PRIVATE KEY-----PRIVATEKEYINCODE-----END RSA PRIVATE KEY-----";

...and needless to say...it didn't work :(

Any ideas? pointers? suggestions???

raam86
  • 6,785
  • 2
  • 31
  • 46
bianca
  • 7,004
  • 12
  • 43
  • 58

6 Answers6

31

The answer is unfortunately as easy as it is simple: No, it is not possible.

The underlying libcurl actually has an API for providing keys and certs directly from memory, but the PHP/CURL extension only has support for providing them as files!

Bonus material:

If you're sure that your libcurl is built with OpenSSL, you can actually use the CURLOPT_SSL_CTX_FUNCTION option to do it. However:

  1. that makes it an libcurl+OpenSSL specific solution

  2. I don't think PHP/CURL exposes that function (enough) to allow this. You would probably need to extend the binding code first...

(I should add that I am the main author and maintainer of libcurl.)

Daniel Stenberg
  • 54,736
  • 17
  • 146
  • 222
  • There are special filenames, supported by PHP and one of them is `php://memory` stream. Does libcurl support such filename? (not tested) – lisachenko Jun 14 '12 at 06:24
  • I don't know. If they work as regular files to libcurl then they will work, but I doubt they do so my guess would be that they don't work... – Daniel Stenberg Jun 14 '12 at 06:55
  • @Alexander: For options with string values (e.g.: CURLOPT_URL, CURLOPT_SSLCERT, etc.), `php-curl` simply converts the passed value to a C-string and pass it directly to `libcurl`. Since `libcurl` knows nothing about `php://memory`, it's not possible. – netcoder Jun 14 '12 at 15:08
  • @netcoder I found workaround for this in the bug report: https://bugs.php.net/bug.php?id=43468. CURLOPT_READFUNCTION can be used to add a support for such stream to the CURL. Need to check that... – lisachenko Jun 15 '12 at 05:46
  • @Alexander: no, that's not true. You cannot pass a key to libcurl with the user of the read callback. – Daniel Stenberg Jun 18 '12 at 07:17
  • 3
    @DanielStenberg It's been several years since you addressed this question. Can you provide an update on this? Does libcurl now have the API to pass in cert and key files as a string? Some situations ultimately require the keys to be saved in a file unencrypted (not good!) before using curl. – Josh Bradley Jun 08 '17 at 02:29
16

Using tmpfile() might suffice as a workaround.

$tempPemFile = tmpfile();
fwrite($tempPemFile, $pemfile);
$tempPemPath = stream_get_meta_data($tempPemFile);
$tempPemPath = $tempPemPath['uri'];

and then:

curl_setopt($ch, CURLOPT_SSLCERT, $tempPemPath); 

but make sure you close it after so the tmp file is delete

fclose($tempPemFile);
MDrollette
  • 6,887
  • 1
  • 36
  • 49
  • Doesn't work on Windows PHP 7.4.21. CURL also complains about an invalid certificate (beacause it cannot read it from tmpfile). file_get_contents($tempPemPath) returns an empty string. I also tried adding fflush($tempPemFile) but the behavior didn't change. I suggest using tempnam() function and handling temp files manually. – Andrey Radomanov Nov 17 '22 at 19:45
4

You could create temporary files, write the strings into the files and then point to the temp files...

2

CURLOPT_SSLCERT_BLOB is now supported by PHP and the linked CURL It is available as of PHP 8.1.0 and cURL 7.71.0.

This mean you can pass private keys as memory/string

https://bugs.php.net/bug.php?id=81085 is how i found out; it obviously also has samples how to use, in the unit tests

https://patch-diff.githubusercontent.com/raw/php/php-src/pull/7194.patch

basically

$clientCert = file_get_contents($clientCertPathPEMFile);
$clientKey = file_get_contents($clientKeyPathPEMFile);

curl_setopt($ch, CURLOPT_SSLCERT_BLOB, $clientCert);
curl_setopt($ch, CURLOPT_SSLKEY_BLOB, $clientKey);
Daniel
  • 21
  • 2
  • Hey can you add more details please ? – mbesson Nov 03 '22 at 18:46
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 03 '22 at 18:46
  • tried to explain more - better? – Daniel Nov 04 '22 at 10:08
0

Let's say that you have the certificate text in $cert_in_text and KEY in the $key_text.

  1. I suggest using the tempnam() function to get the temporary filename.
  2. To avoid problems with accessing system's temp folder in restricted web-server environment, I suggest using the sys_get_temp_dir() function which will set temp directory from the php.ini of the current web server.
  3. Then write text contents of the certificate and the key to temporary file using the file_put_contents() function.
  4. To ensure that important information is removed from the file system, I suggest registering the later unlink() function call with the register_shutdown_function().

Here is the example:

$tmpfile = tempnam(sys_get_temp_dir(),'');
file_put_contents($tmpfile, $cert_text);
register_shutdown_function('unlink',$tmpfile);

curl_setopt($ch, CURLOPT_SSLCERT, $tmpfile);

$tmpfile = tempnam(sys_get_temp_dir(),'');
file_put_contents($tmpfile, $key_text);
register_shutdown_function('unlink',$tmpfile);

curl_setopt($ch, CURLOPT_SSLKEY, $tmpfile);
Andrey Radomanov
  • 1,777
  • 1
  • 13
  • 6
-2

I'm not SSL Expert but CURLOPT_SSLKEY is private.pem file of the CURLOPT_SSLCERT public.pem file?

My parameters

CURLOPT_CAINFO => /path/cacert.pem
CURLOPT_SSLKEY => /path/private.pem
CURLOPT_SSLCERT => /path/public.pem

Try my suggested answer and let me know if it is helpful or not.

Seraly
  • 1
  • 2