使用 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
。由于libcurl
对php://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
在 php 中使用 curl 与单独文件中的客户端证书和私钥
Laravel 的微信插件 EasyWechat 出现 curl 60错误
[PHP] curl: (60) SSL certificate problem: unable to get local issuer certificate