使用 xmldsig 语法签名的 XML 有 3 个重要部分:
-
Signature -> KeyInfo
包含有关从用于对数据进行签名的私钥派生的公钥的信息
-
Signature -> SignedInfo
包含将使用上述私钥签名的数据;数据包含有关如何计算验证的信息,例如:、 、CanonicalizationMethod
SignatureMethod
Reference
-
Signature -> SignatureValue
包含使用私钥签名时生成的签名的值Signature -> SignedInfo
从理论上讲,这就是代码应该如何查找 rsa-sha1 算法(由 指定),具有以下规范化方法:独占 XML 规范化 1.0(省略注释)和提供的 x509 证书:Signature -> SignedInfo -> SignatureMethod
$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($xmlString);
$xpath = new DOMXPath($xmlDoc);
$xpath->registerNamespace('secdsig', 'http://www.w3.org/2000/09/xmldsig#');
// fetch Signature node from XML
$query = ".//secdsig:Signature";
$nodeset = $xpath->query($query, $xmlDoc);
$signatureNode = $nodeset->item(0);
// fetch SignedInfo node from XML
$query = "./secdsig:SignedInfo";
$nodeset = $xpath->query($query, $signatureNode);
$signedInfoNode = $nodeset->item(0);
// canonicalize SignedInfo using the method descried in
// ./secdsig:SignedInfo/secdsig:CanonicalizationMethod/@Algorithm
$signedInfoNodeCanonicalized = $signedInfoNode->C14N(true, false);
// fetch the x509 certificate from XML
$query = 'string(./secdsig:KeyInfo/secdsig:X509Data/secdsig:X509Certificate)';
$x509cert = $xpath->evaluate($query, $signatureNode);
// we have to re-wrap the certificate from XML to respect the PEM standard
$x509cert = "-----BEGIN CERTIFICATE-----\n"
. $x509cert . "\n"
. "-----END CERTIFICATE-----";
// fetch public key from x509 certificate
$publicKey = openssl_get_publickey($x509cert);
// fetch the signature from XML
$query = 'string(./secdsig:SignatureValue)';
$signature = base64_decode($xpath->evaluate($query, $signatureNode));
// verify the signature
$ok = openssl_verify($signedInfoNodeCanonicalized, $signature, $publicKey);
这个库在php中实现xmldsig方面做得很好:xmlseclibs;如何验证 xmldsig 的示例可以在这里找到:https://github.com/robrichards/xmlseclibs/blob/master/tests/xmlsec-verify.phpt。这个库还验证了 的摘要值,我在上面省略了一个步骤。Signature -> SignedInfo -> Reference