2

我正在尝试为我的 PHP SOAP 客户端实现 WS-Security。第一步是能够从传出请求中生成有效的 XML 摘要,但我无法做到这一点。几天来我一直在寻找答案,但大多数答案最终都是“不要自己解决,只需使用现有的 Java 库”。这在我目前的情况下是不可行的。

我一直在网上查看几个示例,试图重现他们拥有的相同摘要,例如来自 Microsoft的这个。该页面列出了以下示例:

<ds:Object Id="ts-text">
    Wed Jun  4 12:11:06 EDT
</ds:Object>

然后他们显示预期的摘要值:

<ds:Reference URI="#ts-text">
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <ds:DigestValue>pN3j2OeC0+/kCatpvy1dYfG1g68=</ds:DigestValue>
</ds:Reference>

这是我用来计算摘要值的代码:

<?php
$digest = base64_encode(hash('SHA1', $contents, true));

我尝试了许多不同的组合来删除空格或仅使用没有 XML 标记的时间戳但没有成功。我还尝试了需要规范化的更复杂的示例。这是我的单元测试之一:

public function testCreateDigest(DOMDocument $request, $expectedDigest) {

    $ns = $request->documentElement->namespaceURI;
    $body = $request
            ->getElementsByTagNameNS($ns, 'Body')
            ->item(0);

    $firstElement = '';
    foreach($body->childNodes as $node){
        if ($node->nodeType === XML_ELEMENT_NODE) {
            $firstElement = $node;
            break;
        }
    }


    $content = $firstElement->C14N(false, true);


    $actualDigest = base64_encode(hash('SHA1', $content, true));

    $this->assertEquals($expectedDigest, $actualDigest);

}

我到底应该散列什么?我错过了任何步骤吗?

4

1 回答 1

2

我找到了解决方案。对于我尝试的大多数示例,所需的转换是带有注释的独家规范化:http: //www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/#WithComments

所以我的问题是我做错了转换。PHP 的 C14N 函数中的第一个参数定义是否使用排他转换。这就是代码应该是的(请注意,我删除了对第一个元素的不必要遍历):

public function testCreateDigest(DOMDocument $request, $expectedDigest) {

    $ns = $request->documentElement->namespaceURI;
    $body = $request
        ->getElementsByTagNameNS($ns, 'Body')
        ->item(0);

    $content = $body->C14N(true, true); // <-- exclusive, with comments

    $actualDigest = base64_encode(hash('SHA1', $content, true));

    $this->assertEquals($expectedDigest, $actualDigest);

}

所以你有它。这提醒我在漫无目的地编码之前仔细检查我的 XML 并理解标准。

于 2013-09-18T03:59:50.593 回答