From 863146c55fbc4ff6d860cb7bf0d34c1003c6033f Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Tue, 29 Jan 2008 15:17:15 +0000 Subject: [PATCH] Added XML validator helper class. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@214 44740490-163a-0410-bde0-09ae8108e29a --- lib/SimpleSAML/XML/Validator.php | 136 +++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 lib/SimpleSAML/XML/Validator.php diff --git a/lib/SimpleSAML/XML/Validator.php b/lib/SimpleSAML/XML/Validator.php new file mode 100644 index 000000000..0feeeafd3 --- /dev/null +++ b/lib/SimpleSAML/XML/Validator.php @@ -0,0 +1,136 @@ +<?php + +/** + * This class implements helper functions for XML validation. + */ +class SimpleSAML_XML_Validator { + + /** + * This variable contains the XML document we have validated. + */ + private $xmlDocument; + + /** + * This variable contains the fingerprint of the certificate the XML document + * was signed with. + */ + private $x509Fingerprint; + + /** + * This variable contains the nodes which are signed. + */ + private $validNodes = null; + + + /** + * This function initializes the validator. + * + * @param $xmlDocument The XML document we should validate. + * @param $idAttribute The ID attribute which is used in node references. If this attribute is + * NULL (the default), then we will use whatever is the default ID. + */ + public function __construct($xmlDocument, $idAttribute = NULL) { + assert('$xmlDocument instanceof DOMDocument'); + + $this->xmlDocument = $xmlDocument; + + /* Create an XML security object. */ + $objXMLSecDSig = new XMLSecurityDSig(); + + /* Add the id attribute if the user passed in an id attribute. */ + if($idAttribute !== NULL) { + assert('is_string($idAttribute)'); + $objXMLSecDSig->idKeys[] = $idAttribute; + } + + /* Locate the XMLDSig Signature element to be used. */ + $signatureElement = $objXMLSecDSig->locateSignature($this->xmlDocument); + if (!$signatureElement) { + throw new Exception('Could not locate XML Signature element.'); + } + + /* Canonicalize the XMLDSig SignedInfo element in the message. */ + $objXMLSecDSig->canonicalizeSignedInfo(); + + /* Validate referenced xml nodes. */ + if (!$objXMLSecDSig->validateReference()) { + throw new Exception('XMLsec: digest validation failed'); + } + + + /* Find the key used to sign the document. */ + $objKey = $objXMLSecDSig->locateKey(); + if (empty($objKey)) { + throw new Exception('Error loading key to handle XML signature'); + } + + /* Load the key data. */ + if (!XMLSecEnc::staticLocateKeyInfo($objKey, $signatureElement)) { + throw new Exception('Error finding key data for XML signature validation.'); + } + + /* Check the signature. */ + if (! $objXMLSecDSig->verify($objKey)) { + throw new Exception("Unable to validate Signature"); + } + + /* Extract the certificate fingerprint. */ + $this->x509Fingerprint = $objKey->getX509Fingerprint(); + + /* Find the list of validated nodes. */ + $this->validNodes = $objXMLSecDSig->getValidatedNodes(); + } + + + /** + * This function validates that the fingerprint of the certificate which was used to + * sign this document matches the given fingerprint. An exception will be thrown if + * the fingerprints doesn't match. + * + * @param $fingerprint The fingerprint which should match. + */ + public function validateFingerprint($fingerprint) { + assert('is_string($fingerprint)'); + + if($this->x509Fingerprint === NULL) { + throw new Exception('Key used to sign the message wasn\'t an X509 certificate.'); + } + + /* Make sure that the fingerprint is in the correct format. */ + $fingerprint = strtolower(str_replace(":", "", $fingerprint)); + + /* Compare the fingerprints. Throw an exception if they didn't match. */ + if ($fingerprint !== $this->x509Fingerprint) { + throw new Exception('Expecting certificate fingerprint [' . $fingerprint . ']but got [' . $this->x509Fingerprint . ']'); + } + + /* The fingerprints matched. */ + } + + + /** + * This function checks if the given XML node was signed. + * + * @param $node The XML node which we should verify that was signed. + * + * @return TRUE if this node (or a parent node) was signed. FALSE if not. + */ + public function isNodeValidated($node) { + assert('$node instanceof DOMNode'); + + while($node !== NULL) { + if(in_array($node, $this->validNodes)) { + return TRUE; + } + + $node = $node->parentNode; + } + + /* Neither this node nor any of the parent nodes could be found in the list of + * signed nodes. + */ + return FALSE; + } +} + +?> \ No newline at end of file -- GitLab