/** * Validates a signature (Message or Assertion). * * @param string|DomDocument $xml The element we should validate * @param string|null $cert The pubic cert * @param string|null $fingerprint The fingerprint of the public cert */ public static function validateSign($xml, $cert = null, $fingerprint = null) { if ($xml instanceof DOMDocument) { $dom = clone $xml; } else { if ($xml instanceof DOMElement) { $dom = clone $xml->ownerDocument; } else { $dom = new DOMDocument(); $dom = self::loadXML($dom, $xml); } } $objXMLSecDSig = new XMLSecurityDSig(); $objXMLSecDSig->idKeys = array('ID'); $objDSig = $objXMLSecDSig->locateSignature($dom); if (!$objDSig) { throw new Exception('Cannot locate Signature Node'); } $objKey = $objXMLSecDSig->locateKey(); if (!$objKey) { throw new Exception('We have no idea about the key'); } $objXMLSecDSig->canonicalizeSignedInfo(); try { $retVal = $objXMLSecDSig->validateReference(); } catch (Exception $e) { throw $e; } XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig); if (!empty($cert)) { $objKey->loadKey($cert, false, true); return $objXMLSecDSig->verify($objKey) === 1; } else { $domCert = $objKey->getX509Certificate(); $domCertFingerprint = OneLogin_Saml2_Utils::calculateX509Fingerprint($domCert); if (OneLogin_Saml2_Utils::formatFingerPrint($fingerprint) !== $domCertFingerprint) { return false; } else { $objKey->loadKey($domCert, false, true); return $objXMLSecDSig->verify($objKey) === 1; } } }
/** * Tests the validateSign method of the OneLogin_Saml2_Utils * * @covers OneLogin_Saml2_Utils::validateSign */ public function testValidateSign() { $settingsDir = TEST_ROOT . '/settings/'; include $settingsDir . 'settings1.php'; $settings = new OneLogin_Saml2_Settings($settingsInfo); $idpData = $settings->getIdPData(); $cert = $idpData['x509cert']; $fingerprint = OneLogin_Saml2_Utils::calculateX509Fingerprint($cert); $xmlMetadataSigned = file_get_contents(TEST_ROOT . '/data/metadata/signed_metadata_settings1.xml'); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlMetadataSigned, $cert)); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlMetadataSigned, null, $fingerprint)); $xmlResponseMsgSigned = base64_decode(file_get_contents(TEST_ROOT . '/data/responses/signed_message_response.xml.base64')); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlResponseMsgSigned, $cert)); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlResponseMsgSigned, null, $fingerprint)); $xmlResponseAssertSigned = base64_decode(file_get_contents(TEST_ROOT . '/data/responses/signed_assertion_response.xml.base64')); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlResponseAssertSigned, $cert)); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlResponseAssertSigned, null, $fingerprint)); $xmlResponseDoubleSigned = base64_decode(file_get_contents(TEST_ROOT . '/data/responses/double_signed_response.xml.base64')); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlResponseDoubleSigned, $cert)); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($xmlResponseDoubleSigned, null, $fingerprint)); $dom = new DOMDocument(); $dom->loadXML($xmlResponseMsgSigned); $this->assertTrue(OneLogin_Saml2_Utils::validateSign($dom, $cert)); $dom->firstChild->firstChild->nodeValue = 'https://example.com/other-idp'; try { $this->assertFalse(OneLogin_Saml2_Utils::validateSign($dom, $cert)); $this->assertTrue(false); } catch (Exception $e) { $this->assertContains('Reference validation failed', $e->getMessage()); } $dom2 = new DOMDocument(); $dom2->loadXML($xmlResponseMsgSigned); $assertElem = $dom2->firstChild->firstChild->nextSibling->nextSibling; $this->assertTrue(OneLogin_Saml2_Utils::validateSign($assertElem, $cert)); $dom3 = new DOMDocument(); $dom3->loadXML($xmlResponseMsgSigned); $dom3->firstChild->firstChild->nodeValue = 'https://example.com/other-idp'; $assertElem2 = $dom3->firstChild->firstChild->nextSibling->nextSibling; try { $this->assertTrue(OneLogin_Saml2_Utils::validateSign($assertElem2, $cert)); $this->assertTrue(false); } catch (Exception $e) { $this->assertContains('Reference validation failed', $e->getMessage()); } $invalidFingerprint = 'afe71c34ef740bc87434be13a2263d31271da1f9'; $this->assertFalse(OneLogin_Saml2_Utils::validateSign($xmlMetadataSigned, null, $invalidFingerprint)); $noSigned = base64_decode(file_get_contents(TEST_ROOT . '/data/responses/invalids/no_signature.xml.base64')); try { $this->assertFalse(OneLogin_Saml2_Utils::validateSign($noSigned, $cert)); $this->assertTrue(false); } catch (Exception $e) { $this->assertContains('Cannot locate Signature Node', $e->getMessage()); } $noKey = base64_decode(file_get_contents(TEST_ROOT . '/data/responses/invalids/no_key.xml.base64')); try { $this->assertFalse(OneLogin_Saml2_Utils::validateSign($noKey, $cert)); $this->assertTrue(false); } catch (Exception $e) { $this->assertContains('We have no idea about the key', $e->getMessage()); } }
/** * Tests the isValid method of the OneLogin_Saml2_Response * Case valid response2 * * @covers OneLogin_Saml2_Response::isValid */ public function testIsValid2() { $xml = file_get_contents(TEST_ROOT . '/data/responses/valid_response.xml.base64'); $settingsDir = TEST_ROOT . '/settings/'; include $settingsDir . 'settings1.php'; $settingsInfo['idp']['certFingerprint'] = OneLogin_Saml2_Utils::calculateX509Fingerprint($settingsInfo['idp']['x509cert']); $settingsInfo['idp']['x509cert'] = null; $settings = new OneLogin_Saml2_Settings($settingsInfo); $response = new OneLogin_Saml2_Response($settings, $xml); $this->assertTrue($response->isValid()); }
/** * Validates a signature (Message or Assertion). * * @param string|DomDocument $xml The element we should validate * @param string|null $cert The pubic cert * @param string|null $fingerprint The fingerprint of the public cert * @param string|null $fingerprintalg The algorithm used to get the fingerprint */ public static function validateSign($xml, $cert = null, $fingerprint = null, $fingerprintalg = 'sha1') { if ($xml instanceof DOMDocument) { $dom = clone $xml; } else { if ($xml instanceof DOMElement) { $dom = clone $xml->ownerDocument; } else { $dom = new DOMDocument(); $dom = self::loadXML($dom, $xml); } } # Check if Reference URI is empty try { $signatureElems = $dom->getElementsByTagName('Signature'); foreach ($signatureElems as $signatureElem) { $referenceElems = $dom->getElementsByTagName('Reference'); if (count($referenceElems) > 0) { $referenceElem = $referenceElems->item(0); if ($referenceElem->getAttribute('URI') == '') { $referenceElem->setAttribute('URI', '#' . $signatureElem->parentNode->getAttribute('ID')); } } } } catch (Exception $e) { continue; } $objXMLSecDSig = new XMLSecurityDSig(); $objXMLSecDSig->idKeys = array('ID'); $objDSig = $objXMLSecDSig->locateSignature($dom); if (!$objDSig) { throw new Exception('Cannot locate Signature Node'); } $objKey = $objXMLSecDSig->locateKey(); if (!$objKey) { throw new Exception('We have no idea about the key'); } $objXMLSecDSig->canonicalizeSignedInfo(); try { $retVal = $objXMLSecDSig->validateReference(); } catch (Exception $e) { throw $e; } XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig); if (!empty($cert)) { $objKey->loadKey($cert, false, true); return $objXMLSecDSig->verify($objKey) === 1; } else { $domCert = $objKey->getX509Certificate(); $domCertFingerprint = OneLogin_Saml2_Utils::calculateX509Fingerprint($domCert, $fingerprintalg); if (OneLogin_Saml2_Utils::formatFingerPrint($fingerprint) !== $domCertFingerprint) { return false; } else { $objKey->loadKey($domCert, false, true); return $objXMLSecDSig->verify($objKey) === 1; } } }