PHP 使用证书实现 XML 数字签名和验签( SHA256 with RSA)

用秘钥给XML报文添加签名域(具体用到什么样的签名方式请看 github 上面的测试用例)

首先

需要安装扩展 xmlseclibs
地址:https://github.com/robrichards/xmlseclibs

然后

看下面示例(github上面也有测试的调用示例)

/**
 * generateXMLSignFields XML生成签名域
 * Use sha256withrsa algorithm to generate XML internal signature
 * @param $xml
 * @return string
 * @throws \Exception
 * @author   liuml  
 * @DateTime 2018/12/21  16:37
 */
protected function generateXMLSignFields($xml, $prefix = 'ds')
{
    // 加载要签名的XML
    $doc = new \DOMDocument();
    $doc->loadXML($xml);

    // 创建一个新的安全对象
    $objDSig = new XMLSecurityDSig($prefix);
    // 使用c14n专属规范化
    $objDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
    // 签名使用 SHA-256
    $objDSig->addReference(
        $doc,
        XMLSecurityDSig::SHA1,
        ['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],
        ['force_uri' => true]
    );

    // 创建一个新的(私有)安全密钥
    $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']);

    // 如果密钥有密码,则使用它进行设置
    // $objKey->passphrase = '';

    // 加载私钥
    $objKey->loadKey("-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->privateKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----\n");

    // 对XML文件签名
    $objDSig->sign($objKey);

    // 将关联的公钥添加到签名
    // $objDSig->add509Cert("-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->publicKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----\n");

    // 将签名附加到XML
    $objDSig->appendSignature($doc->documentElement);
    // saveXML 里面 LIBXML_NOEMPTYTAG 是为了不简写空值的标签。例:(  => )
    // 也可以直接这样写 return $doc->saveXML();
    return $doc->saveXML($doc->documentElement, LIBXML_NOEMPTYTAG);
}

/**
 * checkResponseSign 验证签名
 * Validate signatures in XML
 * @param $xml
 * @return bool
 * @throws \Exception
 * @author   liuml  
 * @DateTime 2018/12/21  17:51
 */
protected function checkResponseSign($xml)
{
    $doc = new \DOMDocument();
    $doc->loadXML($xml);
    $objXMLSecDSig = new XMLSecurityDSig();

    $objDSig = $objXMLSecDSig->locateSignature($doc);
    if (!$objDSig) {
        throw new \Exception("Cannot locate Signature Node");
    }
    $objXMLSecDSig->canonicalizeSignedInfo();
    $objXMLSecDSig->idKeys = array('wsu:Id');
    $objXMLSecDSig->idNS   = array('wsu' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd');

    $retVal = $objXMLSecDSig->validateReference();
    if (!$retVal) {
        throw new \Exception("Reference Validation Failed");
    }

    $objKey = $objXMLSecDSig->locateKey();
    if (!$objKey) {
        throw new \Exception("We have no idea about the key");
    }

    $key = NULL;

    $objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);

    if (!$objKeyInfo->key && empty($key)) {
        $objKey->loadKey("-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->myBankPublicKey, 64, "\n",true) . "\n-----END PUBLIC KEY-----\n");
    }

    if ($objXMLSecDSig->verify($objKey) === 1) {
        return true;
    } else {
        return false;
    }
}

你可能感兴趣的:(PHP)