Подтвердить что ты не робот

Проверка цифровой подписи в ответе SAML на сертификат в PHP

Я новичок в сертификате SSL. поэтому немного осторожно о том, что я сделал до сих пор. Я создаю приложение, использующее SSO для аутентификации пользователей с использованием PHP 5.4. Что у меня есть:  сертификат (.pfx), предоставленный стороной.  зашифрованный SAML в переменной POST.

De-crypted xml почти похож на SAML: почему сертификат внутри Подписи?

Мне нужно проверить, что ответ получен от проверенного провайдера. Я узнал, что в нем есть проблема .pem вместо .pfx. Поэтому я преобразовал файл .pfx в .pem с помощью команд ssl. Я использовал код из 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);

Так что я должен игнорировать X509Certificate, встроенный в xml, или мне нужно проверить его также... будет openssl_verify достаточно? и я на правильном пути? пожалуйста, любые рекомендации будут оценены.

4b9b3361

Ответ 1

XML, подписанный с использованием xmldsig содержит 3 важные части:

  • Signature -> KeyInfo содержит информацию об открытом ключе, полученном из закрытого ключа, используемого для подписи данных.
  • Signature -> SignedInfo содержит данные, которые будут подписаны с использованием закрытого ключа, упомянутого выше; данные содержат информацию о том, как должна вычисляться проверка, например: CanonicalizationMethod, SignatureMethod, Reference
  • Signature -> SignatureValue содержит значение сигнатуры, сгенерированной подписью Signature -> SignedInfo с закрытым ключом

Теоретически именно так код должен искать алгоритм rsa-sha1 (указанный Signature -> SignedInfo -> SignatureMethod), имеющий следующий метод канонизации: Исключительный XML Canonicalization 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 отлично работает при реализации xmldsig в ​​php: xmlseclibs; пример того, как проверить xmldsig, можно найти здесь: https://github.com/robrichards/xmlseclibs/blob/master/tests/xmlsec-verify.phpt. Эта библиотека также проверяет значение дайджеста от Signature -> SignedInfo -> Reference, шаг, который я пропустил выше.

Ответ 2

Я предлагаю вам использовать https://github.com/lightSAML/lightSAML. Он использует xmlseclibs и реализует полный профиль SOML SSO SP. Простой прием ответа SAML из HTTP POST и проверка его образцов подписи приведены в поваренной книге LightSAML 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/, и весь код будет выглядеть следующим образом:

$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