尝试在 PHP 中使用 x.509 证书对 SOAP 调用进行数字签名
Posted
技术标签:
【中文标题】尝试在 PHP 中使用 x.509 证书对 SOAP 调用进行数字签名【英文标题】:Trying to digitally sign SOAP call with x.509 certificate in PHP 【发布时间】:2016-02-15 06:01:08 【问题描述】:我正在与客户合作,尝试使用 php 发送和接收肥皂电话。他们设置了 ws-security,并使用 x.509 证书进行身份验证。我已经能够使用 SoapUI 让它工作,但我无法在 PHP 中使用它。
我遇到的问题是,他们不使用标准的二进制安全令牌或用户名/密码组合。他们改为在安全令牌参考中签署 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();
必须有一种方法可以轻松做到这一点,但我似乎错过了它。以前有人做过吗?
【问题讨论】:
你有没有考虑过因为内容不同而导致签名不同?另外,我相信对于您的具体情况,二进制令牌需要添加到$objKey
而不是 $objWSSE
。
XMLSecurityKey
- 你不应该使用这个类的 RobRichards 版本吗?
【参考方案1】:
据我所知,您使用了错误的密钥类型:它应该是XMLSecurityKey::DSA_SHA1
,但您使用的是XMLSecurityKey::RSA_SHA1
。顺便说一句,lib不支持第一个。但是还是可以解决的。您可以在下面找到我用来测试的代码。
-
生成密钥 (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
-
修补库:
在 vendor/robrichards/xmlseclibs/src/XMLSecurityKey.php
第 216 行添加以下 case 块:
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;
-
运行签名功能:
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();
-
以下是我通过上面的 sn-p 设法获得的 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>
【讨论】:
抱歉格式化 - 所以会以某种方式破坏它。我还创建了一个 git 来提供帮助:gist.github.com/t1gor/af58fdc4c7bf91dd4ad50528638b92bc。希望这有助于解决您的问题。以上是关于尝试在 PHP 中使用 x.509 证书对 SOAP 调用进行数字签名的主要内容,如果未能解决你的问题,请参考以下文章