在PHP中验证SAML响应中的数字签名与证书

时间:2013-10-23 09:59:45

标签: php ssl ssl-certificate saml

我是SSL证书的新手。对我到目前为止所做的事情有点谨慎。 我正在创建一个使用SSO来验证使用PHP 5.4的用户的应用程序。 是)我有的:  党提供的证书(.pfx)。  在POST变量中加密SAML。

去加密的xml与SAML: Why is the certificate within the Signature?

几乎相似

我需要验证响应是来自经过验证的提供者。我在google搜索时已经知道我需要.pem而不是.pfx,所以我已经使用ssl命令将.pfx文件转换为.pem了。我使用了http://www.php.net/manual/es/function.openssl-verify.php#62526中的代码。这是我的代码。

$encxml=$_POST['SAMLResponse'];
$xml = new SimpleXMLElement(base64_decode($encxml)); 
$signature = ((string)$xml->Signature->SignatureValue);
var_dump($signature);


//do I need to do something with this X509Certificate value embedded in xml??
$cert = ((string)$xml->Signature->KeyInfo->X509Data->X509Certificate);
var_dump($cert);

//Or I need
$fp = fopen("xyz.pem", "r");
$priv_key = fread($fp, 8192);
fclose($fp);
print_r($priv_key);
$ok = openssl_verify($xml, $signature, $priv_key);

所以我应该忽略xml中嵌入的X509Certificate还是我需要检查它... openssl_verify会不会足够?我是在正确的道路上吗?欢迎任何指导。

2 个答案:

答案 0 :(得分:20)

使用xmldsig语法签名的XML有三个重要部分:

  1. Signature -> KeyInfo包含有关从用于签署数据的私钥派生的公钥的信息
  2. Signature -> SignedInfo包含将使用上述私钥签名的数据;数据包含有关如何计算验证的信息,例如:CanonicalizationMethodSignatureMethodReference
  3. Signature -> SignatureValue包含使用私钥对Signature -> SignedInfo进行签名而生成的签名的值
  4. 理论上,这是代码应该如何查找rsa-sha1算法(由Signature -> SignedInfo -> SignatureMethod指定),具有以下规范化方法:独占XML规范化1.0(省略注释),以及提供的x509证书:

    $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);    
    

    这个lib在php中实现xmldsig方面做得很好:xmlseclibs;可以在此处找到如何验证xmldsig的示例:https://github.com/robrichards/xmlseclibs/blob/master/tests/xmlsec-verify.phpt。该库还验证来自Signature -> SignedInfo -> Reference的摘要值,这是我在上面省略的步骤。

答案 1 :(得分:1)

我建议您使用https://github.com/lightSAML/lightSAML。它使用xmlseclibs并实现完整的SAML SSO SP配置文件。在LightSAML cookbook http://www.lightsaml.com/LightSAML-Core/Cookbook/How-to-receive-SAML-message/http://www.lightsaml.com/LightSAML-Core/Cookbook/How-to-verify-signature-of-SAML-message/中给出了从HTTP POST简单接收SAML响应并验证其签名样本的信息,整个代码看起来像这样

$request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();

$bindingFactory = new \LightSaml\Binding\BindingFactory();
$binding = $bindingFactory->getBindingByRequest($request);

$messageContext = new \LightSaml\Context\Profile\MessageContext();
/** @var \LightSaml\Model\Protocol\Response $response */
$response = $binding->receive($request, $messageContext);

$key = \LightSaml\Credential\KeyHelper::createPublicKey(
    \LightSaml\Credential\X509Certificate::fromFile(__DIR__.'/../web/sp/saml.crt')
);

/** @var \LightSaml\Model\XmlDSig\SignatureXmlReader $signatureReader */
$signatureReader = $authnRequest->getSignature();

try {
    $ok = $signatureReader->validate($key);

    if ($ok) {
        print "Signaure OK\n";
    } else {
        print "Signature not validated";
    }
} catch (\Exception $ex) {
    print "Signature validation failed\n";
}

通过完整SAML SSO配置文件特定操作处理响应有点多,对于这些详细信息,您可以在https://github.com/lightSAML/lightSAML/blob/master/web/sp/acs.php中查看示例,或者如果您正在使用Symfony https://github.com/lightSAML/SpBundle