使用 PHP 在 Curl 中将 .PEM 和 .KEY 作为字符串传递

Posted

技术标签:

【中文标题】使用 PHP 在 Curl 中将 .PEM 和 .KEY 作为字符串传递【英文标题】:Passing .PEM and .KEY as string in Curl using PHP 【发布时间】:2011-12-19 00:32:37 【问题描述】:

我有一个 CERT 和私钥文件。我正在使用 cUrl 和 php 连接到另一个服务。目前,我已经在文件中获得证书和密钥,并且使用以下代码可以正常工作:

$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);

我的问题是:我可以将证书和密钥作为字符串传递而不是作为文件传递吗?我尝试简单地将各个文件的内容作为字符串传递,如下所示:

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

...不用说...它没有工作:(

有什么想法吗?指针?建议???

【问题讨论】:

请问您提供的是哪个.key 文件?我只有.pem 文件。 【参考方案1】:

不幸的是,答案很简单:不,这是不可能的。

底层的 libcurl 实际上有一个 API 可以直接从内存中提供密钥和证书,但是 PHP/CURL 扩展只支持将它们作为文件提供!

奖励材料:

如果您确定您的 libcurl 是使用 OpenSSL 构建的,您实际上可以使用 CURLOPT_SSL_CTX_FUNCTION 选项来执行此操作。然而:

    这使它成为 libcurl+OpenSSL 特定的解决方案

    我认为 PHP/CURL 没有公开该函数(足够)以允许这样做。您可能需要先扩展绑定代码...

(我应该补充一点,我是 libcurl 的主要作者和维护者。)

【讨论】:

有一些特殊的文件名,PHP 支持,其中之一是php://memory 流。 libcurl 是否支持这样的文件名? (未测试) 我不知道。如果它们作为 libcurl 的常规文件工作,那么它们将起作用,但我怀疑它们是否这样做,我的猜测是它们不起作用...... @Alexander:对于带有字符串值的选项(例如:CURLOPT_URL、CURLOPT_SSLCERT 等),php-curl 只是将传递的值转换为 C 字符串并直接传递给 libcurl。由于libcurlphp://memory 一无所知,所以这是不可能的。 @netcoder 我在错误报告中找到了解决方法:bugs.php.net/bug.php?id=43468。 CURLOPT_READFUNCTION 可用于向 CURL 添加对此类流的支持。需要检查... @DanielStenberg 您解决这个问题已经有好几年了。你能提供一个更新吗? libcurl 现在是否有 API 可以将证书和密钥文件作为字符串传递?在某些情况下,最终需要在使用 curl 之前将密钥保存在未加密的文件中(不好!)。【参考方案2】:

使用tmpfile() 可能足以解决问题。

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

然后:

curl_setopt($ch, CURLOPT_SSLCERT, $tempPemPath); 

但请确保在删除 tmp 文件后关闭它

fclose($tempPemFile);

【讨论】:

【参考方案3】:

您可以创建临时文件,将字符串写入文件,然后指向临时文件...

【讨论】:

【参考方案4】:

我不是 SSL 专家,但 CURLOPT_SSLKEY 是 CURLOPT_SSLCERT public.pem 文件的 private.pem 文件?

我的参数

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

试试我建议的答案,让我知道它是否有帮助。

【讨论】:

以上是关于使用 PHP 在 Curl 中将 .PEM 和 .KEY 作为字符串传递的主要内容,如果未能解决你的问题,请参考以下文章

SSL/TLS 操作失败 PHP5.6 - curl-ca-bundle.crt & cacert.pem

curl 证书错误问题解决办法

在 php 中使用 curl 与单独文件中的客户端证书和私钥

php curl_errno 60

Laravel 的微信插件 EasyWechat 出现 curl 60错误

[PHP] curl: (60) SSL certificate problem: unable to get local issuer certificate