php - 尝试在 PHP 中使用 x.509 证书对 SOAP 调用进行数字签名

标签 php xml web-services soap ws-security

我正在与客户合作,尝试使用 PHP 发送和接收 soap 调用。他们设置了 ws-security,并使用 x.509 证书进行身份验证。我已经能够使用 SoapUI 使其正常工作,但我无法在 PHP 中使用它。

我遇到的问题是,他们不使用标准的二进制安全 token 或用户名/密码组合。他们改为在安全 token 引用中签署 XML 文件。

我一直在尝试使用 Rob Richards 的库来生成散列,它似乎包含了代码来完成我正在尝试做的事情,但我一直没有成功实现它。 (https://github.com/robrichards/wse-php)

这是我们应该得到的:

<soapenv:Envelope xmlns:ord="http://order.pine.cypresscare.com" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <ds:Signature Id="SIG-17020931F46DA4F12E144355764463230" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                    <ec:InclusiveNamespaces PrefixList="ord soapenv" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:CanonicalizationMethod>
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
                <ds:Reference URI="#id-17020931F46DA4F12E144355764463229">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                            <ec:InclusiveNamespaces PrefixList="ord" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </ds:Transform>
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <ds:DigestValue>BZc+DagseonF6kbBdtONG73wjcE=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>eIICrWiZerxelcSNUack5OKgvdSKYS3p5KdblFLVztYksExNoZ9wLQ==</ds:SignatureValue>
            <ds:KeyInfo Id="KI-17020931F46DA4F12E144355764463227">
                <wsse:SecurityTokenReference wsu:Id="STR-17020931F46DA4F12E144355764463228">
                    <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
                         MIID... (Hash goes here)
                    </wsse:KeyIdentifier>
                </wsse:SecurityTokenReference>
            </ds:KeyInfo>
        </ds:Signature>
    </wsse:Security>
</soapenv:Header>

但我能得到的最好的是:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ord="http://order.pine.cypresscare.com">
<soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
        <wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="pfx7b827e06-1662-e6e4-78fd-6b4bb95aeb96" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
            MIIC... (Hash goes here)
        </wsse:BinarySecurityToken>
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <ds:Reference URI="#pfx0b88133b-03ed-8bbc-8c8a-4998ef427a3a">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <ds:DigestValue>fPmwf05DIdXW4K9muNYR6LMXjnI=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>q36Dr2TIl1OE0/6bBMPb0dQRVCimwpOx7KeYyUCfxMZVIMvDBXxH+lCiB5xEgEH/aceUsn19b0GTU1LqISOk4/rhVBHGw2Wpq/jBcRZWOO54xZYdpGkqzepagazJWOWVVdDCAD7WpQV34KRu1rT4S4ZCjaOeApVIlI2nhPWRXVQ=</ds:SignatureValue>
            <ds:KeyInfo>
                <wsse:SecurityTokenReference>
                    <wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#pfx7b827e06-1662-e6e4-78fd-6b4bb95aeb96"/>
                </wsse:SecurityTokenReference>
            </ds:KeyInfo>
        </ds:Signature>
    </wsse:Security>
</soapenv:Header>

以及使这一切正常工作的 PHP 类:

<?php
class MySoap extends SoapClient {
    public function __doRequest($request, $location, $saction, $version) {
        $doc = new DOMDocument('1.0');
        $doc->loadXML($request);

        $objWSSE = new WSSESoap($doc);

        /* add Timestamp with no expiration timestamp */
        $objWSSE->addTimestamp();

        /* create new XMLSec Key using AES256_CBC and type is private key */
        $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));

        /* load the private key from file - last arg is bool if key in file (true) or is string (false) */
        $objKey->loadKey("c:\\xampp\htdocs\\XMLSoapApp\\cert1.pem", $isFile=true, true);

        /* Sign the message - also signs appropiate WS-Security items */
        $options = array("insertBefore" => true);

        $objWSSE->signSoapDoc($objKey, $options);

        /* Add certificate (BinarySecurityToken) to the message */ 
        $token = $objWSSE->addBinaryToken(file_get_contents(combine_key));

        /* Attach pointer to Signature */
        $objWSSE->attachTokentoSig($token);
        return $doc->saveXML();
    }
}

必须有一种方法可以轻松做到这一点,但我似乎错过了它。以前有人这样做过吗?

最佳答案

据我所知,您使用了错误的 key 类型:它应该是 XMLSecurityKey::DSA_SHA1,但您使用的是 XMLSecurityKey::RSA_SHA1。顺便说一句,lib 不支持第一个。但是还是可以解决的。您可以在下面找到我用来测试它的代码。

  1. 生成 key (great hint):
openssl dsa -in dsakey.private
openssl req -x509 -new -days 3650 -key dsakey.private -out dsakey.cert
openssl dsa -in dsakey.private -pubout -out dsakey.pub
  1. 修补库:

vendor/robrichards/xmlseclibs/src/XMLSecurityKey.php 第 216 行添加以下 case block :

case (self::DSA_SHA1):
  $this->cryptParams['library'] = 'openssl';
  $this->cryptParams['method']  = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
  $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
  $this->cryptParams['digest']  = OPENSSL_ALGO_SHA1;
  if (is_array($params) && ! empty($params['type'])) {
    if ($params['type'] == 'public' || $params['type'] == 'private') {
      $this->cryptParams['type'] = $params['type'];
      break;
    }
  }
  throw new Exception('Certificate "type" (private/public) must be passed via parameters');
break;
  1. 运行签名功能:

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

$doc = new DOMDocument('1.0');
$doc->loadXML(file_get_contents('/request.xml'));

$objWSSE = new WSSESoap($doc);
$objWSSE->addTimestamp();

$objKey = new XMLSecurityKey(XMLSecurityKey::DSA_SHA1, ['type' => 'private']);

$objKey->loadKey('/dsakey.private', true);
$options = ['insertBefore' => true];
$objWSSE->signSoapDoc($objKey, $options);

$token = $objWSSE->addBinaryToken(file_get_contents('/dsakey.cret'));
$objWSSE->attachTokentoSig($token);

echo $doc->saveXML();

  1. 下面是我通过上面的代码片段获得的 XML 代码:

<?xml version="1.0" encoding="UTF-8"?>
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
       <soap:Header>
          <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soap:mustUnderstand="1">
             <wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="pfxc329505d-b83f-6587-529d-912489ee428d" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">MIICmTCCAlUCCQCe8BUic962uDALBglghkgBZQMEAwIwLzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MB4XDTE4MTIyMTA3MDYwMVoXDTI4MTIxODA3MDYwMVowLzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MIIBtzCCASwGByqGSM44BAEwggEfAoGBAJWpUD+1sbgTDnFcettpFJ1WitrZDisZHolCRsM6kRBot1NKvSvdF4ib6lAVV0zHc4pQ4UnaKV6/Dao+4XA52h6zwjFLGItYLbLeZgVslCiTTwuO8FbNpNaNvXb44Mw2JOnHtawXdaQZQ7CxTqNbmU2Lucw2xfU3qfi6c+9AOeZxAhUA82+xkInDY2H6tsooX+Oy1MUxyUcCgYEAi9AGHj0ZGNU32Ob64CKyOfWvZlqa6DviVS7uhZSaz+EX1pzbKTtYGUQHTvVHJAuUB8kD1ZKtDN7oT9yRHAA05CVqZ/75Lck4E5K4Tf1dKyLmPWKz37pZ2rnu0RahPy544G2ltRKerKtfMGd05D6qFACbX0vCN/utQkiKtxRP4vkDgYQAAoGAefPHsusLAYDgxSdRmXb8lf9/2mBzzFH4aei1osOGwst+Sczm01WqC0wrg4VTZIUecx3n7fotWsR6JPVkjt9z27qdbNw5Fw+tGXXKjUU/NeG9zU3gAO1dw97mpz4Dm4ahi2eF75w9rMvSYZDpPSuc2VlDn6DofNHZm4nofg0WbrkwCwYJYIZIAWUDBAMCAzEAMC4CFQDNtN7oK33NGn4PzH37ypQCR5NrPgIVALAPzeGOG4HiPCfLSnUnodR+jRXQ</wsse:BinarySecurityToken>
             <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                   <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                   <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
                   <ds:Reference URI="#pfxcd7e3884-68fd-dd2c-ce2e-a0f2db73d6b0">
                      <ds:Transforms>
                         <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                      </ds:Transforms>
                      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                      <ds:DigestValue>RndT24MzjzRczZbfuqMp68c5fxI=</ds:DigestValue>
                   </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>MC0CFQCjMCTZUSQSPSBtvp5Kq3rzXvf+YQIURYBRUczJ/3ZMpQzqdQ3k6s/D1Qk=</ds:SignatureValue>
                <ds:KeyInfo>
                   <wsse:SecurityTokenReference>
                      <wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#pfxc329505d-b83f-6587-529d-912489ee428d" />
                   </wsse:SecurityTokenReference>
                </ds:KeyInfo>
             </ds:Signature>
             <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="pfxcd7e3884-68fd-dd2c-ce2e-a0f2db73d6b0">
                <wsu:Created>2018-12-21T07:11:57Z</wsu:Created>
                <wsu:Expires>2018-12-21T08:11:57Z</wsu:Expires>
             </wsu:Timestamp>
          </wsse:Security>
       </soap:Header>
    </soap:Envelope>

关于php - 尝试在 PHP 中使用 x.509 证书对 SOAP 调用进行数字签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33696404/

相关文章:

java - 获取JAVA PID PHP

php - 为什么使用 json 的 javascript 库选择 [ { } , { } ] 结构

php - 检查是否设置了多个 POST 参数的最简单方法?

c# - 如何在 Visual Studio 中为生产环境配置 Web 引用

java - 无法解析复杂类型的属性

php - 除非刷新,否则写入文本文件不会更新

xml - 如何使用xerces C++获取节点值

java - 在 XMLConfiguration 文件中记录更改

java - Sun Xml doclet 仍然可用吗?

javascript - 在网站上显示准确的本地时间?