'); define('PRIVATE_PEM', ''); define('PRIVATE_PASSPHRASE', ''); define('canonMethod', "http://www.w3.org/2001/10/xml-exc-c14n"); define('XMLDSIG_TMPL', 'xmldsig.xml'); /* need to generate GUIDs to be used within document for reference points */ function generate_GUID() { /* prefix to be used for all GUIDs */ $prefix = 'wsse-'; $uuid = md5(uniqid(rand(), true)); $guid = $prefix.substr($uuid,0,8)."-". substr($uuid,8,4)."-". substr($uuid,12,4)."-". substr($uuid,16,4)."-". substr($uuid,20,12); return $guid; } /* Functions to generate Exclusive Canonical XML */ function sortAndAddAttrs($element, $arAtts) { $newAtts = array(); foreach ($arAtts AS $attnode) { $newAtts[$attnode->nodeName] = $attnode; } ksort($newAtts); foreach ($newAtts as $attnode) { $element->setAttribute($attnode->nodeName, $attnode->nodeValue); } } function canonical($tree, $element, $withcomments) { if ($tree->nodeType != XML_DOCUMENT_NODE) { $dom = $tree->ownerDocument; } else { $dom = $tree; } if ($element->nodeType != XML_ELEMENT_NODE) { if ($element->nodeType == XML_COMMENT_NODE && ! $withcomments) { return; } $tree->appendChild($dom->importNode($element, TRUE)); return; } $arNS = array(); if ($element->namespaceURI != "") { if ($element->prefix == "") { $elCopy = $dom->createElementNS($element->namespaceURI, $element->nodeName); } else { $prefix = $tree->lookupPrefix($element->namespaceURI); if ($prefix == $element->prefix) { $elCopy = $dom->createElementNS($element->namespaceURI, $element->nodeName); } else { $elCopy = $dom->createElement($element->nodeName); $arNS[$element->namespaceURI] = $element->prefix; } } } else { $elCopy = $dom->createElement($element->nodeName); } $tree->appendChild($elCopy); /* Create DOMXPath based on original document */ $xPath = new DOMXPath($element->ownerDocument); /* Get namespaced attributes */ $arAtts = $xPath->query('attribute::*[namespace-uri(.) != ""]', $element); /* Create an array with namespace URIs as keys, and sort them */ foreach ($arAtts AS $attnode) { if (array_key_exists($attnode->namespaceURI, $arNS) && ($arNS[$attnode->namespaceURI] == $attnode->prefix)) { continue; } $prefix = $tree->lookupPrefix($attnode->namespaceURI); if ($prefix != $attnode->prefix) { $arNS[$attnode->namespaceURI] = $attnode->prefix; } else { $arNS[$attnode->namespaceURI] = NULL; } } if (count($arNS) > 0) { asort($arNS); } /* Add namespace nodes */ foreach ($arNS AS $namespaceURI=>$prefix) { if ($prefix != NULL) { $elCopy->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:".$prefix, $namespaceURI); } } if (count($arNS) > 0) { ksort($arNS); } /* Get attributes not in a namespace, and then sort and add them */ $arAtts = $xPath->query('attribute::*[namespace-uri(.) = ""]', $element); sortAndAddAttrs($elCopy, $arAtts); /* Loop through the URIs, and then sort and add attributes within that namespace */ foreach ($arNS as $nsURI=>$prefix) { $arAtts = $xPath->query('attribute::*[namespace-uri(.) = "'.$nsURI.'"]', $element); sortAndAddAttrs($elCopy, $arAtts); } foreach ($element->childNodes AS $node) { canonical($elCopy, $node, $withcomments); } } function C14NGeneral($element, $exclusive=FALSE, $withcomments=FALSE) { /* IF PHP 5.2+ then use built in canonical functionality */ $php_version = explode('.', PHP_VERSION); if (($php_version[0] > 5) || ($php_version[0] == 5 && $php_version[1] >= 2) ) { return $element->C14N(TRUE, FALSE); } /* Must be element */ if (! $element instanceof DOMElement) { return NULL; } /* Currently only exclusive XML is supported */ if ($exclusive == FALSE) { return NULL; } $copyDoc = new DOMDocument(); canonical($copyDoc, $element, $withcomments); return $copyDoc->saveXML($copyDoc->documentElement, LIBXML_NOEMPTYTAG); } /* End Functions to generate Exclusive Canonical XML */ class mySoap extends SoapClient { function __doRequest($request, $location, $saction, $version) { $dom = new DOMDocument('1.0'); $dom->loadXML($request); $root = $dom->documentElement; $root->setAttributeNS("http://www.w3.org/2000/xmlns/", 'xmlns:wsse', "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); /* Namespace for WS-Utility (Timestamp/Created/Expires) */ $root->setAttributeNS("http://www.w3.org/2000/xmlns/", 'xmlns:wsu', "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"); $path = new DOMXPath($dom); $headers = $path->query('//SOAP-ENV:Envelope/SOAP-ENV:Header'); if ($headers->length == 0) { $header = $dom->createElementNS($root->namespaceURI, 'SOAP-ENV:Header'); $root->insertBefore($header, $root->firstChild); } else { $header = $headers->item(0); } $xPath = new DOMXPath($dom); $headers = $xPath->query('//SOAP-ENV:Envelope/SOAP-ENV:Body'); $sBody = $headers->item(0); /* Generate the wsse:Security element and require that it be understood */ $security = $dom->createElementNS('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'wsse:Security'); $header->appendChild($security); $security->setAttributeNS($root->namespaceURI, 'SOAP-ENV:mustunderstand', '1'); /* Add the WSU timestamps */ $utility = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'; $timestamp = $dom->createElementNS($utility, 'wsu:Timestamp'); $security->appendChild($timestamp); $created = $dom->createElementNS($utility, 'wsu:Created', date ("Y-m-d\TH:i:s").'Z'); $timestamp->appendChild($created); /* Add the Id attribute */ $wsuCreatedID = generate_GUID(); $created->setAttributeNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Id", $wsuCreatedID); /* Load the certificate and add to message */ $token = file_get_contents(PUBLIC_CERT); $binsectoken = $dom->createElementNS('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'wsse:BinarySecurityToken', $token); $security->appendChild($binsectoken); $securityTokenID = generate_GUID(); $binsectoken->setAttribute('ValueType', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'); $binsectoken->setAttribute('EncodingType', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'); $binsectoken->setAttributeNS('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'wsu:Id', $securityTokenID); /* load signature template */ $sigtpl = new DOMDocument(); $sigtpl->load(XMLDSIG_TMPL); $sig = $dom->importNode($sigtpl->documentElement, TRUE); $security->appendChild($sig); $wsuID = generate_GUID(); $sBody->setAttributeNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Id", $wsuID); /* Following line split into two lines due tobecause of length */ $query = '//*[local-name()="Reference" and '. 'namespace-uri()="http://www.w3.org/2000/09/xmldsig#"]'; $nodeset = $xPath->query($query); $refElement = $nodeset->item(0); /* Clone and append additional reference node */ $refClone = $refElement->cloneNode(TRUE); $nextRef = $refElement->nextSibling; if ($nextRef && $nextRef->nodeType != XML_ELEMENT_NODE) { $nextRef = $nextRef->nextSibling; } $refElement->parentNode->insertBefore($refClone, $nextRef); $arNodes = array(array($wsuCreatedID, $refClone), array($wsuID, $refElement)); foreach ($arNodes AS $key=>$arRef) { $wsuID = $arRef[0]; $refElement = $arRef[1]; $refElement->setAttribute("URI", '#'.$wsuID); $query = '//*[@wsu:Id="'.$wsuID.'"]'; $nodeset = $xPath->query($query); $toSign = $nodeset->item(0); $query = './/*[local-name()="DigestMethod" and namespace-uri()="http://www.w3.org/2000/09/xmldsig#"]'; $nodeset = $xPath->query($query, $refElement); $digMethod = $nodeset->item(0); /* Perform canonicalization exclusive/without comments */ $canonical = C14NGeneral($toSign, TRUE); /* Create SHA1 hash of the canonical form of the Object element */ $hash = sha1($canonical); $bhash = pack("H*", $hash); $digValue = base64_encode($bhash); /* Following is done in example only to add proper whitespacing */ $addPrev = NULL; $addPost = NULL; if ($digMethod->previousSibling->nodeType == XML_TEXT_NODE) { $addPrev = clone $digMethod->previousSibling; } if ($digMethod->nextSibling->nodeType == XML_TEXT_NODE) { $addPost = clone $digMethod->nextSibling; } /* End custom whitespaces */ /* Create DigestValue element, and append to parent of DigestMethod */ $digestValue = $dom->createElementNS("http://www.w3.org/2000/09/xmldsig#", "DigestValue", $digValue); $digMethod->parentNode->appendChild($digestValue); } /* END arRef loop */ /* Retrieve SignedInfo element */ $query = '//*[local-name()="SignedInfo" and '. 'namespace-uri()="http://www.w3.org/2000/09/xmldsig#"]'; $nodeset = $xPath->query($query); $signedInfo = $nodeset->item(0); /* Perform canonicalization exclusive/without comments */ $canonical = C14NGeneral($signedInfo, TRUE); $fp=fopen(PRIVATE_PEM,"r"); $priv_key=fread($fp,8192); fclose($fp); $res = openssl_get_privatekey($priv_key, PRIVATE_PASSPHRASE); openssl_sign($canonical, $hmac, $res); openssl_free_key($res); $bhmac = base64_encode($hmac); $sigValue = $dom->createElementNS("http://www.w3.org/2000/09/xmldsig#", "SignatureValue", $bhmac); $signedInfo->parentNode->appendChild($sigValue); $signedInfo->parentNode->appendChild(new DOMText("\n")); $keyInfo = $dom->createElementNS("http://www.w3.org/2000/09/xmldsig#", "KeyInfo"); $signedInfo->parentNode->appendChild($keyInfo); $SecurityTokenReference = $dom->createElementNS('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'wsse:SecurityTokenReference'); $keyInfo->appendChild($SecurityTokenReference); $Reference = $dom->createElementNS('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'wsse:Reference'); $SecurityTokenReference->appendChild($Reference); $Reference->setAttribute('URI', '#'.$securityTokenID); $Reference->setAttribute('ValueType', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'); $request = $dom->saveXML(); return parent::__doRequest($request, $location, $saction, $version); } } ?>