【问题标题】:curl / soap request with .p12 SSL certificate带有 .p12 SSL 证书的 curl / soap 请求
【发布时间】:2018-09-29 18:57:17
【问题描述】:

我需要使用 PHP7.2 请求 https://address?wsdl 的 SOAP 请求 .p12 证书。

经过数小时的研究,我唯一能做的就是从 bash 发出这个请求:

$ curl -k -E cert.crt.pem --key cert.key.pem https://address?wsdl

它返回了 WSDL。但是我不得不将.p12 拆分为单独的文件并使用-k 选项,这使得所有这些东西都不安全。 通过此命令完成拆分:

openssl pkcs12 -in mycert.p12 -out cert.key.pem -nocerts -nodes
openssl pkcs12 -in mycert.p12 -out cert.crt.pem -clcerts -nokeys

问题是: 如何使用 PHP 中的 cURL 请求此 WSDL 或如何配置 new \SoapClient() 使其正常工作?

这可能只有.p12 文件和密码吗?还是我必须转换它?


希望这描述了我已经能够做到的事情:

<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_VERBOSE, true);

/**
 * cert.p12 (with password) -> cert.pem (contains encrypted PKey & client ?unencrypted? cert)
 * $ openssl pkcs12 -in cert.p12 -out cert.pem -clcerts
 *
 * Result:
 *
 * This works. But:
 * - I don't have peer verification
 * - Is such file safe? It has encrypted pkey & certificate (I think not encrypted).
 *   I don't know much about that topic. Maybe someone with more experience will be able to tell more.
 *   Maybe some better solution to output this. Maybe as 2 separate files?
 */
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); // DO NOT VERIFY!
curl_setopt($ch,CURLOPT_SSLCERT,__DIR__ . '/cert.pem');
//curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $pass); // This is not required :/
curl_setopt($ch,CURLOPT_SSLKEY,__DIR__ . '/cert.pem');
curl_setopt($ch,CURLOPT_SSLKEYPASSWD, $pass);

/**
 * cert.p12 (with password) -> cert.pem (contains encrypted PKey & client ?unencrypted? cert)
 * $ openssl pkcs12 -in cert.p12 -out cert.pem -clcerts
 *
 * Result:
 *
 * TCP_NODELAY set
 * Connected to XXX
 * ALPN, offering http/1.1
 * SSL certificate problem: self signed certificate in certificate chain
 * stopped the pause stream!
 * Closing connection 0
 */
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,true);
curl_setopt($ch,CURLOPT_SSLCERT,__DIR__ . '/cert.pem');
curl_setopt($ch,CURLOPT_SSLKEY,__DIR__ . '/cert.pem');
curl_setopt($ch,CURLOPT_SSLKEYPASSWD, $pass);

/**
 * cert.p12 (with password) -> cert.pem (contains encrypted PKey & client ?unencrypted? cert)
 * $ openssl pkcs12 -in cert.p12 -out cert.pem -clcerts
 *
 * Result:
 *
 * TCP_NODELAY set
 * Connected to XXX
 * ALPN, offering http/1.1
 * ignoring certificate verify locations due to disabled peer verification
 * error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
 * stopped the pause stream!
 * Closing connection 0
 */
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch,CURLOPT_CAINFO,__DIR__ . '/cert.pem');
curl_setopt($ch,CURLOPT_CAPATH,__DIR__);
curl_setopt($ch,CURLOPT_KEYPASSWD,$pass);

/**
 * cert.p12 (with password) -> cert.pem (contains encrypted PKey & client ?unencrypted? cert)
 * $ openssl pkcs12 -in cert.p12 -out cert.pem -clcerts
 *
 * Result:
 *
 * TCP_NODELAY set
 * Connected to XXX
 * ALPN, offering http/1.1
 * successfully set certificate verify locations:
 *   CAfile: /www/soap/cert.pem
 *   CApath: /www/soap
 * SSL certificate problem: self signed certificate in certificate chain
 * stopped the pause stream!
 * Closing connection 0
 */
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch,CURLOPT_CAINFO,__DIR__ . '/cert.pem');
curl_setopt($ch,CURLOPT_CAPATH,__DIR__);
curl_setopt($ch,CURLOPT_KEYPASSWD,$pass);

$data = curl_exec($ch);

$error = curl_error($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);

var_dump($data, $httpcode, $error);
?>

【问题讨论】:

  • 你必须在 CURL 请求中使用什么代码才能使用该证书但不起作用?
  • 插入了一些代码和结果。我应该首先这样做:)
  • 看过并尝试过这个?似乎你在混合命令参数 - stackoverflow.com/questions/27062639/…
  • 是的,我做到了。到处都有很多误导性的答案,包括 curl 不接受 p12 证书。卷曲和肥皂都为我工作。 SOAP 使用 stream_context_create,它允许我设置 allow_self_signed=true。所以我真正遇到的最后一个问题是:SSL certificate problem: self signed certificate in certificate chain。现在我必须找出如何忽略这个问题(不仅仅是我有解决方法)。之后,我将发布我如何解决 curl 和 soap 的所有 .p12 问题。如果您能帮我解决这个自签名证书,我会很高兴。
  • stackoverflow.com/questions/21187946/… ?看来您需要更加注意并检查证书链,因为它告诉您,而不是尝试解决它。​​

标签: php ssl soap php-curl


【解决方案1】:

我无法直接使用.p12.pfxpkcs12 是 SOAP。 首先我们需要读取p12文件并将其转换为.pem。稍后您可以缓存结果($pemCertContent)以避免转换每个请求或将其存储为文件以用作文件路径。

    $readSuccessful = openssl_pkcs12_read($content, $certData, $password);
    if (!$readSuccessful) {
        $msg = sprintf('Could not read pkcs12 file `%s`: `%s`.', $filePath, openssl_error_string());
        throw new \Exception($msg);
    }

    $pemCertContent = '';

    if (isset($certData['pkey'])) {
        openssl_pkey_export($certData['pkey'], $pem, $pemPassword);
        $pemCertContent .= $pem;
    }
    if (isset($certData['cert'])) {
        openssl_x509_export($certData['cert'], $cert);
        $pemCertContent .= $cert;
    }

    $pemCertContent; // This is your .pem certificate content. I store it as a file.

根据需要,您可以在创建 SOAP 客户端时像这样使用它:

    $soapOptions = [
        /* In some cases, when you have 2 certificates you may need to use stream context instead of 'local_cert'
        'stream_context' => stream_context_create([
            'ssl' => [
                'cafile' => $caCert->getFilePath(), // CA Certificate
                'local_cert' => $tlsCertificate->getFilePath(), // PEM certificate
                'passphrase' => $tlsCertificatePass, // Pass for PEM certificate
            ],
        ]),
         */
        'local_cert' => $tlsCertificate->getFilePath(),
        'passphrase' => $tlsCertificatePass,

        'trace' => true,
        'exceptions' => true,
    ];

这允许连接到 SoapServer 以获取 wsdl 并执行请求。就我而言,我还必须用WSSE 签署整个请求正文。为此,我将其与openssl_pkcs12_read 函数打开的.p12 证书一起使用:

RobRichards\WsePhp\WSSESoap;
RobRichards\XMLSecLibs\XMLSecurityKey;

但这是另一回事了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 2020-12-09
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    相关资源
    最近更新 更多