snowiow/x509ds

X509签名库

0.1.0 2018-06-07 06:02 UTC

This package is not auto-updated.

Last update: 2024-09-21 00:34:31 UTC


README

Build Status Coverage Status

简介

X509DS是一个库,可以帮助处理向X509认证请求添加数字签名节点的繁琐过程。一个X509请求通常看起来像这样

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
  <wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing/" soapenv:actor="" soapenv:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
  </wsa:Action>
  <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:actor="" soapenv:mustUnderstand="1">
    <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="timestamp">
      <wsu:Created>2015-12-16T13:39:36Z</wsu:Created>
      <wsu:Expires>2015-12-16T13:44:36Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:BinarySecurityToken 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" 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" wsu:Id="binarytoken">MII...</wsse:BinarySecurityToken>
  </wsse:Security>
</soapenv:Header>
<soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="body">
  <RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
    <TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
    <RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</RequestType>
  </RequestSecurityToken>
</soapenv:Body>
</soapenv:Envelope>

大多数情况下,您希望将签名附加到头文件中,该文件会散列并规范化XML文档的一些节点。最终,整个签名节点将使用您的x509证书的私钥进行签名。生成的XML文档将看起来像这样

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
  <wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing/" soapenv:actor="" soapenv:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
  </wsa:Action>
  <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:actor="" soapenv:mustUnderstand="1">
    <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="timestamp">
      <wsu:Created>2015-12-16T13:39:36Z</wsu:Created>
      <wsu:Expires>2015-12-16T13:44:36Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:BinarySecurityToken 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" 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" wsu:Id="binarytoken"><MII.../wsse:BinarySecurityToken>
  </wsse:Security>
    <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="#body">
                <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>Emk...</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#timestamp">
                <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>2TR...</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#binarytoken">
                <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>/Ntf...</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>tuO...</ds:SignatureValue>
    </ds:Signature>
</soapenv:Header>
<soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="body">
  <RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
    <TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
    <RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</RequestType>
  </RequestSecurityToken>
</soapenv:Body>
</soapenv:Envelope>

创建签名的过程相当繁琐,因为您需要在一方面处理加密和openssl,另一方面处理PHP []DOMDocument](https://secure.php.net/manual/en/dom.setup.php)。此库旨在提供创建数字签名的简单接口。创建数字签名的PHP代码,如前面的示例所示,将看起来像这样

use X509DS\Signer;

$signer = Signer::fromPrivateKey('path/to/pkey');
$signer->setTags(
    [
        'Body'                 => '#body',
        'Timestamp'            => '#timestamp',
        'BinarySecurityToken'  => '#binarytoken',
    ]
);
$signer->setCanonization(Canonization::C14N_EXCLUSIVE);
$document = $signer->sign(self::XML); //The signed DOMDocument
$document->saveXml(); //The signed XML document as a string

如您所见,整个过程不超过4条语句。当然,您可以配置不同的签名构建方式。更多关于此主题的内容,请参阅高级用法部分。

需求

安装

通过composer
composer require snowiow/x509ds

用法

创建签名对象

从私钥或pfx创建。

私钥

// Either from the path of the private key
$signer = Signer::fromPrivateKey('path/to/pkey');
// or the string content of the private key
$signer = Signer::fromPrivateKey(file_get_contents('path/to/pkey'));
// or an openssl resource
$signer = Signer::fromPrivateKey(openssl_pkey_get_private(file_get_contents('path/to/pkey')));

pfx文件

// Either from the path of the pfx file
$signer = Signer::fromPfx('/path/to/pfx', 'password of pfx');
// or the string content of the pfx file
$signer = Signer::fromPfx(file_get_contents('/path/to/pfx'), 'password of pfx');

设置规范化方法。默认:C14N

// Can be one of
$signer->setCanonization(Canonization::C14N); //Default
$signer->setCanonization(Canonization::C14N_EXCLUSIVE);
$signer->setCanonization(Canonization::C14N_WITH_COMMENTS);
$signer->setCanonization(Canonization::C14N_WITH_COMMENTS_EXCLUSIVE);

设置摘要方法。默认:SHA1

// Can be one of
$signer->setDigestMethod(Digest::SHA1); //Default
$signer->setDigestMethod(Digest::SHA256);
$signer->setDigestMethod(Digest::SHA512);
$signer->setDigestMethod(Digest::RIPEMD160);

设置签名方法。默认:SHA1

// Can be one of
$signer->setSignatureMethod(Digest::SHA1); //Default
$signer->setSignatureMethod(Digest::SHA256);
$signer->setSignatureMethod(Digest::SHA512);
$signer->setSignatureMethod(Digest::RIPEMD160);

设置目标。默认:Header

签名节点可以作为子节点附加到任意节点。

// Example values (namespace doesn't need to be given)
$signer->setTarget('Header'); //Default
$signer->setTarget('Body');

设置标签。默认:[]

设置节点名称,您需要在签名中获取摘要值。该方法被称为setTags,因为节点将通过DOMDocument方法getElementsByTagName进行搜索。稍后版本将添加额外的功能,如getElementsByTagNameNSgetElementById。标签必须是一个数组,其中键是节点名称,值是uri,它将作为摘要值的参考节点的属性设置。

// Example
$signer->setTag(
    [
        'Body'                 => '#body',
        'Timestamp'            => '#timestamp',
        'BinarySecurityToken'  => '#binarytoken',
    ]
);

设置安全令牌引用节点(可选)

有时需要额外的安全令牌引用节点。该节点将添加到签名中,并看起来像这样

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <wsse:Reference URI="#binarySecurityToken">
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

uri可以进行配置

// Example
$signer->setSecurityTokenReference('#binarySecurityToken');

签名文档

最后,您可以签名字符文档。这将返回带有签名节点的修改后的DOMDocument

$signedDoc = $signer->sign('path/to/xml'); // from a path
$signedDoc = $signer->sign(file_get_contents('path/to/xml')); // from a content string
// or from a DOMDocument
$document = new DOMDocument();
$document->load('path/to/xml');
$signedDoc = $signer->sign($document);

从pfx文件获取证书

因为pfx文件包含私钥和证书,所以您也可以检索提取的证书,例如将其插入BinarySecurityToken节点

$signer = Signer::fromPfx('/path/to/pfx', 'password of pfx');
$cert = $signer->getCertificate();