Example #1
1
 private function _getComparableXmlString(\DOMNode $node)
 {
     if ($node instanceof \DOMDocument) {
         return $node->C14N();
     }
     $dom = new \DOMDocument();
     $dom->appendChild($dom->importNode($node, true));
     return $dom->C14N();
 }
    /**
     * Test unmarshalling / marshalling of XML with Extensions element
     */
    public function testExtensionOrdering()
    {
        $document = new DOMDocument();
        $document->loadXML(<<<AUTHNREQUEST
<samlp:AuthnRequest
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
  ID="_306f8ec5b618f361c70b6ffb1480eade"
  Version="2.0"
  IssueInstant="2004-12-05T09:21:59Z"
  Destination="https://idp.example.org/SAML2/SSO/Artifact"
  ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
  AssertionConsumerServiceURL="https://sp.example.com/SAML2/SSO/Artifact">
  <saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
  <samlp:Extensions>
      <myns:AttributeList xmlns:myns="urn:mynamespace">
          <myns:Attribute name="UserName" value=""/>
      </myns:AttributeList>
  </samlp:Extensions>
  <samlp:NameIDPolicy
    AllowCreate="true"
    Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
</samlp:AuthnRequest>
AUTHNREQUEST
);
        $authnRequest = new SAML2_AuthnRequest($document->documentElement);
        $this->assertXmlStringEqualsXmlString($document->C14N(), $authnRequest->toUnsignedXML()->C14N());
    }
Example #3
0
    public function testMarshalling()
    {
        $fixtureRequestDom = new DOMDocument();
        $fixtureRequestDom->loadXML(<<<XML
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    ID="_bec424fa5103428909a30ff1e31168327f79474984"
                    Version="2.0"
                    IssueInstant="2007-12-10T11:39:34Z"
                    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                    AssertionConsumerServiceURL="http://moodle.bridge.feide.no/simplesaml/saml2/sp/AssertionConsumerService.php">
    <saml:Issuer>urn:mace:feide.no:services:no.feide.moodle</saml:Issuer>
    <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
                        SPNameQualifier="moodle.bridge.feide.no"
                        AllowCreate="true" />
    <samlp:RequestedAuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
    </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>
XML
, LIBXML_NOBLANKS);
        $request = new SAML2_AuthnRequest($fixtureRequestDom->firstChild);
        $context = $request->getRequestedAuthnContext();
        $this->assertEquals('_bec424fa5103428909a30ff1e31168327f79474984', $request->getId());
        $this->assertEquals('urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport', $context['AuthnContextClassRef'][0]);
        $requestXml = $requestDocument = $request->toUnsignedXML()->ownerDocument->C14N();
        $fixtureXml = $fixtureRequestDom->C14N();
        $this->assertXmlStringEqualsXmlString($requestXml, $fixtureXml, 'Request after Unmarshalling and re-marshalling remains the same');
    }
 protected static function getXMLString($string)
 {
     $doc = new DOMDocument(1.0);
     $doc->preserveWhiteSpace = false;
     $doc->formatOutput = false;
     $doc->loadHTML($string);
     return $doc->C14N();
 }
 /**
  * Test building the DOM message to be sent to the token service.
  */
 public function testBuildRequest()
 {
     $xmlNs = 'http://schema.gspt.net/token/1.0';
     $token = 'abc-123';
     $expected = new DOMDocument();
     $expected->loadXML(sprintf('<TokenValidateRequest xmlns="%s"><Token>%s</Token></TokenValidateRequest>', $xmlNs, $token));
     $cfg = $this->buildCoreConfigRegistry(array('apiXmlNs' => $xmlNs));
     $helper = $this->getHelperMock('eb2ccsr/data', array('getConfigModel'));
     $this->replaceByMock('helper', 'eb2ccsr', $helper);
     $helper->expects($this->once())->method('getConfigModel')->will($this->returnValue($cfg));
     $request = Mage::getModel('eb2ccsr/token_request', array('token' => 'abc-123'));
     $this->assertSame($expected->C14N(), EcomDev_Utils_Reflection::invokeRestrictedMethod($request, '_buildRequest')->C14N());
 }
 private function assertXMLEquals($expectXMLFile, $actualXML)
 {
     $expectDOM = new DOMDocument(1.0);
     $expectDOM->formatOutput = false;
     $expectDOM->preserveWhiteSpace = false;
     $expectDOM->load($expectXMLFile);
     $expectXML = $expectDOM->C14N(true, false);
     $rssDOM = new DOMDocument(1.0);
     $rssDOM->formatOutput = false;
     $rssDOM->preserveWhiteSpace = false;
     $rssDOM->loadXML($actualXML);
     $rssXML = $rssDOM->C14N(true, false);
     $this->assertEquals($expectXML, $rssXML);
 }
 /**
  * Call the API.
  *
  * @param DOMDocument $doc The document to send in the request body
  * @param string $xsdName The basename of the xsd file to validate $doc (The dirname is in config.xml)
  * @param string $uri The uri to send the request to
  * @param int $timeout The amount of time in seconds after which the connection is terminated
  * @param string $adapter The classname of a Zend_Http_Client_Adapter
  * @param Zend_Http_Client $client
  * @param string $apiKey Alternate API Key to use
  * @return string The response from the server
  */
 public function request(DOMDocument $doc, $xsdName, $uri, $timeout = self::DEFAULT_TIMEOUT, $adapter = self::DEFAULT_ADAPTER, Zend_Http_Client $client = null, $apiKey = null)
 {
     if (!$apiKey) {
         $apiKey = Mage::helper('eb2ccore')->getConfigModel()->apiKey;
     }
     $xmlStr = $doc->C14N();
     $logData = array_merge(['rom_request_body' => $xmlStr], $this->_logAppContext);
     $logMessage = 'Validating request.';
     $this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__, $logData));
     $this->schemaValidate($doc, $xsdName);
     $client = $this->_setupClient($client, $apiKey, $uri, $xmlStr, $adapter, $timeout);
     $logData = array_merge(['rom_request_url' => $uri], $this->_logAppContext);
     $logMessage = 'Sending request.';
     $this->_logger->info($logMessage, $this->_context->getMetaData(__CLASS__, $logData));
     try {
         $response = $client->request(self::DEFAULT_METHOD);
         return $this->_processResponse($response, $uri);
     } catch (Zend_Http_Client_Exception $e) {
         return $this->_processException($e, $uri);
     }
 }
Example #8
0
 public function __toString()
 {
     return $this->xml->C14N();
 }
Example #9
0
 /**
  * Checks XML response does not include provided XML.
  * Comparison is done by canonicalizing both xml`s.
  * Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
  *
  * @param $xml
  */
 public function dontSeeSoapResponseIncludes($xml)
 {
     $xml = $this->canonicalize($xml);
     \PHPUnit_Framework_Assert::assertNotContains($xml, $this->xmlResponse->C14N(), "found in XML Response");
 }
Example #10
0
 public static function canonicalize($XMLdoc)
 {
     $dom = new DOMDocument();
     $dom->loadXML($XMLdoc);
     return $dom->C14N(true, false);
 }
Example #11
0
<?php

// This example is from https://github.com/facebook/hhvm/issues/3440
$xml = '<?xml version="1.0"?>' . "\n" . '<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xm' . 'lns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="https://pro' . 'ject.mysite.com/saml/acs" ID="FIMRSP_5990c800-0147-1411-b087-93da9d684e69" IssueInstant="2014-07-21T15:36:06Z" Ver' . 'sion="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://accessuat.mysite.com/fim/sps' . '/saml20/saml20</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:' . 'Status><saml:Assertion ID="Assertion-uuid5990c7c6-0147-19bd-9537-93da9d684e69" IssueInstant="2014-07-21T15:36:06Z" Versi' . 'on="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://accessuat.mysite.com/fim/sps/s' . 'aml20/saml20</saml:Issuer><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.' . '1:nameid-format:unspecified">testjive</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bear' . 'er"><saml:SubjectConfirmationData NotOnOrAfter="2014-07-21T15:46:06Z" Recipient="https://project.mysite.com/saml/a' . 'cs"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2014-07-21T15:26:06Z" NotOnOrAfter="2014-07-2' . '1T15:46:06Z"><saml:AudienceRestriction><saml:Audience>http://project.mysite.com</saml:Audience></saml:AudienceRest' . 'riction></saml:Conditions><saml:AuthnStatement AuthnInstant="2014-07-21T15:36:06Z" SessionIndex="uuid599090e7-0147-15b6-' . '9dfd-93da9d684e69" SessionNotOnOrAfter="2014-07-21T16:36:06Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:na' . 'mes:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:Attribute' . 'Statement><saml:Attribute Name="LastName" NameFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"><saml:Attri' . 'buteValue xsi:type="xs:string">user</saml:AttributeValue></saml:Attribute><saml:Attribute Name="FirstName" NameFormat="u' . 'rn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"><saml:AttributeValue xsi:type="xs:string">Test</saml:AttributeValu' . 'e></saml:Attribute><saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"><saml' . ':AttributeValue xsi:type="xs:string">idam_support@bp.com</saml:AttributeValue></saml:Attribute><saml:Attribute Name="use' . 'r-id" NameFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"><saml:AttributeValue xsi:type="xs:string">testj' . 'ive</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>';
$doc = new DOMDocument();
$res = $doc->loadXML($xml);
$caNode = $doc->C14N(true, false, null, ['xs', 'xsi', 'saml']);
echo md5($caNode);
Example #12
0
    public function testLoop()
    {
        $fixtureResponseDom = new DOMDocument();
        $fixtureResponseDom->loadXML(<<<XML
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                ID="s2a0da3504aff978b0f8c80f6a62c713c4a2f64c5b"
                InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"
                Version="2.0"
                IssueInstant="2007-12-10T11:39:48Z"
                Destination="http://moodle.bridge.feide.no/simplesaml/saml2/sp/AssertionConsumerService.php">
    <saml:Issuer>max.feide.no</saml:Issuer>
    <samlp:Extensions>
        <myns:AttributeList xmlns:myns="urn:mynamespace">
          <myns:Attribute name="UserName" value=""/>
      </myns:AttributeList>
    </samlp:Extensions>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    Version="2.0"
                    ID="s2b7afe8e21a0910d027dfbc94ec4b862e1fbbd9ab"
                    IssueInstant="2007-12-10T11:39:48Z">
        <saml:Issuer>max.feide.no</saml:Issuer>
        <saml:Subject>
            <saml:NameID NameQualifier="max.feide.no" SPNameQualifier="urn:mace:feide.no:services:no.feide.moodle" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">UB/WJAaKAPrSHbqlbcKWu7JktcKY</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2007-12-10T19:39:48Z" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984" Recipient="http://moodle.bridge.feide.no/simplesaml/saml2/sp/AssertionConsumerService.php"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2007-12-10T11:29:48Z" NotOnOrAfter="2007-12-10T19:39:48Z">
            <saml:AudienceRestriction>
                <saml:Audience>urn:mace:feide.no:services:no.feide.moodle</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2007-12-10T11:39:48Z" SessionIndex="s259fad9cad0cf7d2b3b68f42b17d0cfa6668e0201">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="givenName">
                <saml:AttributeValue xsi:type="xs:string">RkVJREUgVGVzdCBVc2VyIChnaXZlbk5hbWUpIMO4w6bDpcOYw4bDhQ==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="eduPersonPrincipalName">
                <saml:AttributeValue xsi:type="xs:string">dGVzdEBmZWlkZS5ubw==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="o">
                <saml:AttributeValue xsi:type="xs:string">VU5JTkVUVA==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="ou">
                <saml:AttributeValue xsi:type="xs:string">VU5JTkVUVA==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="eduPersonOrgDN">
                <saml:AttributeValue xsi:type="xs:string">ZGM9dW5pbmV0dCxkYz1ubw==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="eduPersonPrimaryAffiliation">
                <saml:AttributeValue xsi:type="xs:string">c3R1ZGVudA==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="mail">
                <saml:AttributeValue xsi:type="xs:string">bW9yaWEtc3VwcG9ydEB1bmluZXR0Lm5v</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="preferredLanguage">
                <saml:AttributeValue xsi:type="xs:string">bm8=</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="eduPersonOrgUnitDN">
                <saml:AttributeValue xsi:type="xs:string">b3U9dW5pbmV0dCxvdT1vcmdhbml6YXRpb24sZGM9dW5pbmV0dCxkYz1ubw==</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="sn">
                <saml:AttributeValue xsi:type="xs:string">RkVJREUgVGVzdCBVc2VyIChzbikgw7jDpsOlw5jDhsOF</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="cn">
                <saml:AttributeValue xsi:type="xs:string">RkVJREUgVGVzdCBVc2VyIChjbikgw7jDpsOlw5jDhsOF</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="eduPersonAffiliation">
                <saml:AttributeValue xsi:type="xs:string">ZW1wbG95ZWU=_c3RhZmY=_c3R1ZGVudA==</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>
XML
);
        $request = new SAML2_Response($fixtureResponseDom->firstChild);
        $requestXml = $requestDocument = $request->toUnsignedXML()->ownerDocument->C14N();
        $fixtureXml = $fixtureResponseDom->C14N();
        $this->assertXmlStringEqualsXmlString($fixtureXml, $requestXml, 'Response after Unmarshalling and re-marshalling remains the same');
    }
Example #13
0
 function minify()
 {
     $target = $this->target;
     $minifiedJS = $target['library.js']->content;
     $minifiedJS = preg_replace('~^\\s+~m', '', $minifiedJS);
     $minifiedJS = preg_replace('~^//.*$\\n~m', '', $minifiedJS);
     $minifiedJS = preg_replace('~\\n/\\*[\\w\\W]*?\\*/~', '', $minifiedJS);
     $minifiedCSS = $target['release.css']->content;
     $minifiedCSS = preg_replace('~/\\*[\\w\\W]*?\\*/~', '', $minifiedCSS);
     $minifiedCSS = preg_replace('~^\\s+~m', '', $minifiedCSS);
     $minifiedCSS = preg_replace('~[\\r\\n]~', '', $minifiedCSS);
     $minifiedXSL = null;
     if ($target['release.xsl']->exists) {
         $minifiedXSL = $target['release.xsl']->content;
         $doc = new \DOMDocument();
         $doc->formatOutput = false;
         $doc->preserveWhiteSpace = false;
         $doc->loadXML((string) $minifiedXSL);
         $minifiedXSL = $doc->C14N();
     }
     $minifiedPHP = $target['release.php']->content;
     if ($minifiedJS) {
         $target['minified.js']->content = $minifiedJS;
     }
     if ($minifiedCSS) {
         $target['minified.css']->content = $minifiedCSS;
     }
     if ($minifiedXSL) {
         $target['minified.xsl']->content = so_dom::make($minifiedXSL);
     }
     if ($minifiedPHP) {
         $target['minified.php']->content = $minifiedPHP;
     }
     return $this;
 }
<?php

$doc = new DOMDocument();
var_dump($doc->C14N());
 protected function _verifySignatureXMLElement($publicKey, $xml, $element)
 {
     if (!isset($element['ds:Signature'])) {
         throw new Corto_Module_Bindings_Exception("Element is not signed! " . $xml);
     }
     $document = new DOMDocument();
     $document->loadXML($xml);
     $xp = new DomXPath($document);
     $xp->registerNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
     foreach ($element['ds:Signature']['ds:SignedInfo']['ds:Reference'] as $reference) {
         $referencedUri = $reference['_URI'];
         if (strpos($referencedUri, '#') !== 0) {
             throw new Corto_Module_Bindings_Exception("Unsupported use of URI Reference, I only know XPointers: " . $xml);
         }
         $referencedId = substr($referencedUri, 1);
         $xpathResults = $xp->query("//*[@ID = '{$referencedId}']");
         if ($xpathResults->length === 0) {
             throw new Corto_Module_Bindings_Exception("URI Reference, not found? " . $xml);
         }
         if ($xpathResults->length > 1) {
             throw new Corto_Module_Bindings_Exception("Multiple nodes found for URI Reference? " . $xml);
         }
         $referencedElement = $xpathResults->item(0);
         $referencedDocument = new DomDocument();
         $importedNode = $referencedDocument->importNode($referencedElement->cloneNode(true), true);
         $referencedDocument->appendChild($importedNode);
         $referencedDocumentXml = $referencedDocument->saveXML();
         // First process any transforms
         if (isset($reference['ds:Transforms']['ds:Transform'])) {
             foreach ($reference['ds:Transforms']['ds:Transform'] as $transform) {
                 switch ($transform['_Algorithm']) {
                     case 'http://www.w3.org/2000/09/xmldsig#enveloped-signature':
                         $transformDocument = new DOMDocument();
                         $transformDocument->loadXML($referencedDocumentXml);
                         $transformXpath = new DomXPath($transformDocument);
                         $transformXpath->registerNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
                         $signature = $transformXpath->query(".//ds:Signature", $transformDocument)->item(0);
                         $signature->parentNode->removeChild($signature);
                         $referencedDocumentXml = $transformDocument->saveXML();
                         break;
                     case 'http://www.w3.org/2001/10/xml-exc-c14n#':
                         $nsPrefixes = array();
                         if (isset($transform['ec:InclusiveNamespaces']['_PrefixList'])) {
                             $nsPrefixes = explode(' ', $transform['ec:InclusiveNamespaces']['_PrefixList']);
                         }
                         $transformDocument = new DOMDocument();
                         $transformDocument->loadXML($referencedDocumentXml);
                         $referencedDocumentXml = $transformDocument->C14N(true, false, null, $nsPrefixes);
                         break;
                     default:
                         throw new Corto_Module_Bindings_Exception("Unsupported transform " . $transform['_Algorithm'] . ' on XML: ' . $xml);
                 }
             }
         }
         // Verify the digest over the (transformed) element
         if ($reference['ds:DigestMethod']['_Algorithm'] !== 'http://www.w3.org/2000/09/xmldsig#sha1') {
             throw new Corto_Module_Bindings_Exception("Unsupported DigestMethod " . $reference['ds:DigestMethod']['_Algorithm'] . ' on XML: ' . $xml);
         }
         $ourDigest = sha1($referencedDocumentXml, TRUE);
         $theirDigest = base64_decode($reference['ds:DigestValue']['__v']);
         if ($ourDigest !== $theirDigest) {
             throw new Corto_Module_Bindings_Exception("Digests do not match! on XML: " . $xml);
         }
     }
     // Verify the signature over the SignedInfo (not over the entire document, only over the digest)
     $c14Algorithm = $element['ds:Signature']['ds:SignedInfo']['ds:CanonicalizationMethod']['_Algorithm'];
     if ($c14Algorithm !== 'http://www.w3.org/2001/10/xml-exc-c14n#') {
         throw new Corto_Module_Bindings_Exception("Unsupported CanonicalizationMethod '{$c14Algorithm}' on XML: {$xml}");
     }
     if (!isset($element['ds:Signature']['ds:SignatureValue']['__v'])) {
         throw new Corto_Module_Bindings_Exception("No sigurature value found on element? " . var_export($element, true));
     }
     $signatureAlgorithm = $element['ds:Signature']['ds:SignedInfo']['ds:SignatureMethod']['_Algorithm'];
     if ($signatureAlgorithm !== "http://www.w3.org/2000/09/xmldsig#rsa-sha1") {
         throw new Corto_Module_Bindings_Exception("Unsupported SignatureMethod '{$signatureAlgorithm}' on XML: {$xml}");
     }
     // Find the signed element (like an assertion) in the global document (like a response)
     $id = $element['_ID'];
     $signedElement = $xp->query("//*[@ID = '{$id}']")->item(0);
     $signedInfoNode = $xp->query(".//ds:SignedInfo", $signedElement)->item(0);
     $signedInfoXml = $signedInfoNode->C14N(true, false);
     $signatureValue = $element['ds:Signature']['ds:SignatureValue']['__v'];
     $signatureValue = base64_decode($signatureValue);
     return openssl_verify($signedInfoXml, $signatureValue, $publicKey) == 1;
 }