diff --git a/lib/xmlseclibs.php b/lib/xmlseclibs.php
index 56e5348b2646ae519dd5d4b58414ad3a486b117e..c74b3b2b72324d6826e8f384a17b7867e2546c7d 100644
--- a/lib/xmlseclibs.php
+++ b/lib/xmlseclibs.php
@@ -2,7 +2,7 @@
 /**
  * xmlseclibs.php
  *
- * Copyright (c) 2007, Robert Richards <rrichards@cdatazone.org>.
+ * Copyright (c) 2007-2010, Robert Richards <rrichards@cdatazone.org>.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,9 +35,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @author     Robert Richards <rrichards@cdatazone.org>
- * @copyright  2007 Robert Richards <rrichards@cdatazone.org>
+ * @copyright  2007-2010 Robert Richards <rrichards@cdatazone.org>
  * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
- * @version    1.2.1-dev
+ * @version    1.3.0-dev
  */
 
 /*
@@ -177,8 +177,9 @@ class XMLSecurityKey {
     const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
     const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
     const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
-    const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
     const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
+    const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
+    const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
 
     private $cryptParams = array();
     public $type = 0;
@@ -197,6 +198,9 @@ class XMLSecurityKey {
      */
     private $x509Certificate = NULL;
 
+    /* This variable contains the certificate thunbprint if we have loaded an X509-certificate. */
+    private $X509Thumbprint = NULL;
+
     public function __construct($type, $params=NULL) {
         srand();
         switch ($type) {
@@ -261,6 +265,19 @@ class XMLSecurityKey {
                 }
                 throw new Exception('Certificate "type" (private/public) must be passed via parameters');
                 break;
+            case (XMLSecurityKey::RSA_SHA256):
+                $this->cryptParams['library'] = 'openssl';
+                $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
+                $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+                $this->cryptParams['digest'] = 'SHA256';
+                if (is_array($params) && ! empty($params['type'])) {
+                    if ($params['type'] == 'public' || $params['type'] == 'private') {
+                        $this->cryptParams['type'] = $params['type'];
+                        break;
+                    }
+                }
+                throw new Exception('Certificate "type" (private/public) must be passed via parameters');
+                break;
             default:
                 throw new Exception('Invalid Key Type');
                 return;
@@ -293,6 +310,33 @@ class XMLSecurityKey {
         return $key;
     }
 
+    public static function getRawThumbprint($cert) {
+
+        $arCert = explode("\n", $cert);
+        $data = '';
+        $inData = FALSE;
+
+        foreach ($arCert AS $curData) {
+            if (! $inData) {
+                if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
+                    $inData = TRUE;
+                }
+            } else {
+                if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
+                    $inData = FALSE;
+                    break;
+                }
+                $data .= trim($curData);
+            }
+        }
+
+        if (! empty($data)) {
+            return strtolower(sha1(base64_decode($data)));
+        }
+
+        return NULL;
+    }
+
     public function loadKey($key, $isFile=FALSE, $isCert = FALSE) {
         if ($isFile) {
             $this->key = file_get_contents($key);
@@ -309,6 +353,10 @@ class XMLSecurityKey {
         }
         if ($this->cryptParams['library'] == 'openssl') {
             if ($this->cryptParams['type'] == 'public') {
+                if ($isCert) {
+                    /* Load the thumbprint if this is an X509 certificate. */
+                    $this->X509Thumbprint = self::getRawThumbprint($this->key);
+                }
                 $this->key = openssl_get_publickey($this->key);
             } else {
                 $this->key = openssl_get_privatekey($this->key, $this->passphrase);
@@ -396,15 +444,23 @@ class XMLSecurityKey {
     }
 
     private function signOpenSSL($data) {
-        if (! openssl_sign ($data, $signature, $this->key)) {
-            throw new Exception('Failure Signing Data');
+	    $algo = OPENSSL_ALGO_SHA1;
+	    if (! empty($this->cryptParams['digest'])) {
+	        $algo = $this->cryptParams['digest'];
+	    }
+        if (! openssl_sign ($data, $signature, $this->key, $algo)) {
+            throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo);
             return;
         }
         return $signature;
     }
 
     private function verifyOpenSSL($data, $signature) {
-        return openssl_verify ($data, $signature, $this->key);
+	    $algo = OPENSSL_ALGO_SHA1;
+	    if (! empty($this->cryptParams['digest'])) {
+	        $algo = $this->cryptParams['digest'];
+	    }
+        return openssl_verify ($data, $signature, $this->key, $algo);
     }
 
     public function encryptData($data) {
@@ -512,7 +568,37 @@ class XMLSecurityKey {
     public function getX509Certificate() {
         return $this->x509Certificate;
     }
-    
+
+    /* Get the thumbprint of this X509 certificate.
+     *
+     * Returns:
+     *  The thumbprint as a lowercase 40-character hexadecimal number, or NULL
+     *  if this isn't a X509 certificate.
+     */
+    public function getX509Thumbprint() {
+        return $this->X509Thumbprint;
+    }
+
+
+    /**
+     * Create key from an EncryptedKey-element.
+     *
+     * @param DOMElement $element  The EncryptedKey-element.
+     * @return XMLSecurityKey  The new key.
+     */
+    public static function fromEncryptedKeyElement(DOMElement $element) {
+
+        $objenc = new XMLSecEnc();
+        $objenc->setNode($element);
+        if (! $objKey = $objenc->locateKey()) {
+            throw new Exception("Unable to locate algorithm for this Encrypted Key");
+        }
+        $objKey->isEncrypted = TRUE;
+        $objKey->encryptedCtx = $objenc;
+        XMLSecEnc::staticLocateKeyInfo($objKey, $element);
+        return $objKey;
+    }
+
 }
 
 class XMLSecurityDSig {
@@ -551,6 +637,10 @@ class XMLSecurityDSig {
         $this->sigNode = $sigdoc->documentElement;
     }
 
+    private function resetXPathObj() {
+        $this->xPathCtx = NULL;
+    }
+	
     private function getXPathObj() {
         if (empty($this->xPathCtx) && ! empty($this->sigNode)) {
             $xpath = new DOMXPath($this->sigNode->ownerDocument);
@@ -743,7 +833,7 @@ class XMLSecurityDSig {
                         if ($node->localName == 'InclusiveNamespaces') {
                             if ($pfx = $node->getAttribute('PrefixList')) {
                                 $arpfx = array();
-                                $pfxlist = split(" ", $pfx);
+                                $pfxlist = explode(" ", $pfx);
                                 foreach ($pfxlist AS $pfx) {
                                     $val = trim($pfx);
                                     if (! empty($val)) {
@@ -919,12 +1009,14 @@ class XMLSecurityDSig {
         $prefix_ns = NULL;
         $id_name = 'Id';
         $overwrite_id  = TRUE;
+        $force_uri = FALSE;
 
         if (is_array($options)) {
             $prefix = empty($options['prefix'])?NULL:$options['prefix'];
             $prefix_ns = empty($options['prefix_ns'])?NULL:$options['prefix_ns'];
             $id_name = empty($options['id_name'])?'Id':$options['id_name'];
             $overwrite_id = !isset($options['overwrite'])?TRUE:(bool)$options['overwrite'];
+            $force_uri = !isset($options['force_uri'])?FALSE:(bool)$options['force_uri'];
         }
 
         $attname = $id_name;
@@ -945,6 +1037,8 @@ class XMLSecurityDSig {
                 $node->setAttributeNS($prefix_ns, $attname, $uri);
             }
             $refNode->setAttribute("URI", '#'.$uri);
+        } elseif ($force_uri) {
+            $refNode->setAttribute("URI", '');
         }
 
         $transNodes = $this->createNewSignNode('Transforms');
@@ -954,7 +1048,20 @@ class XMLSecurityDSig {
             foreach ($arTransforms AS $transform) {
                 $transNode = $this->createNewSignNode('Transform');
                 $transNodes->appendChild($transNode);
-                $transNode->setAttribute('Algorithm', $transform);
+                if (is_array($transform) && 
+                    (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116'])) && 
+                    (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']))) {
+                    $transNode->setAttribute('Algorithm', 'http://www.w3.org/TR/1999/REC-xpath-19991116');
+                    $XPathNode = $this->createNewSignNode('XPath', $transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']);
+                    $transNode->appendChild($XPathNode);
+                    if (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'])) {
+                        foreach ($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'] AS $prefix => $namespace) {
+                            $XPathNode->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:$prefix", $namespace);
+                        }
+                    }
+                } else {
+                    $transNode->setAttribute('Algorithm', $transform);
+                }
             }
         } elseif (! empty($this->canonicalMethod)) {
             $transNode = $this->createNewSignNode('Transform');
@@ -1055,7 +1162,13 @@ class XMLSecurityDSig {
         return $objKey->signData($data);
     }
 
-    public function sign($objKey) {
+    public function sign($objKey, $appendToNode = NULL) {
+        // If we have a parent node append it now so C14N properly works
+        if ($appendToNode != NULL) {
+            $this->resetXPathObj();
+            $this->appendSignature($appendToNode);
+            $this->sigNode = $appendToNode->lastChild;
+        }
         if ($xpath = $this->getXPathObj()) {
             $query = "./secdsig:SignedInfo";
             $nodeset = $xpath->query($query, $this->sigNode);
@@ -1093,6 +1206,8 @@ class XMLSecurityDSig {
      *
      * @param $node  The node the signature element should be inserted into.
      * @param $beforeNode  The node the signature element should be located before.
+     * 
+     * @return DOMNode The signature element node
      */
     public function insertSignature($node, $beforeNode = NULL) {
 
@@ -1100,15 +1215,15 @@ class XMLSecurityDSig {
         $signatureElement = $document->importNode($this->sigNode, TRUE);
 
         if($beforeNode == NULL) {
-            $node->insertBefore($signatureElement);
+            return $node->insertBefore($signatureElement);
         } else {
-            $node->insertBefore($signatureElement, $beforeNode);
+            return $node->insertBefore($signatureElement, $beforeNode);
         }
     }
 
     public function appendSignature($parentNode, $insertBefore = FALSE) {
         $beforeNode = $insertBefore ? $parentNode->firstChild : NULL;
-        $this->insertSignature($parentNode, $beforeNode);
+        return $this->insertSignature($parentNode, $beforeNode);
     }
 
     static function get509XCert($cert, $isPEMFormat=TRUE) {
@@ -1228,12 +1343,31 @@ class XMLSecEnc {
     private $rawNode = NULL;
     public $type = NULL;
     public $encKey = NULL;
+    private $references = array();
 
     public function __construct() {
+        $this->_resetTemplate();
+    }
+
+    private function _resetTemplate(){
         $this->encdoc = new DOMDocument();
         $this->encdoc->loadXML(XMLSecEnc::template);
     }
 
+    public function addReference($name, $node, $type) {
+	    if (! $node instanceOf DOMNode) {
+	        throw new Exception('$node is not of type DOMNode');
+	    }
+        $curencdoc = $this->encdoc;
+        $this->_resetTemplate();
+        $encdoc = $this->encdoc;
+        $this->encdoc = $curencdoc;
+        $refuri = XMLSecurityDSig::generate_GUID();
+        $element = $encdoc->documentElement;
+        $element->setAttribute("Id", $refuri);
+	    $this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri);
+    }
+
     public function setNode($node) {
         $this->rawNode = $node;
     }
@@ -1300,6 +1434,26 @@ class XMLSecEnc {
         }
     }
 
+    public function encryptReferences($objKey) {
+        $curRawNode = $this->rawNode;
+        $curType = $this->type;
+        foreach ($this->references AS $name=>$reference) {
+            $this->encdoc = $reference["encnode"];
+            $this->rawNode = $reference["node"];
+            $this->type = $reference["type"];
+            try {
+                $encNode = $this->encryptNode($objKey);
+                $this->references[$name]["encnode"] = $encNode;
+            } catch (Exception $e) {
+                $this->rawNode = $curRawNode;
+                $this->type = $curType;
+                throw $e;
+            }
+        }
+        $this->rawNode = $curRawNode;
+        $this->type = $curType;
+    }
+
     public function decryptNode($objKey, $replace=TRUE) {
         $data = '';
         if (empty($this->rawNode)) {
@@ -1336,10 +1490,11 @@ class XMLSecEnc {
                         } else {
                             $doc = $this->rawNode->ownerDocument;
                         }
-                        $newFrag = $doc->createDOMDocumentFragment();
+                        $newFrag = $doc->createDocumentFragment();
                         $newFrag->appendXML($decrypted);
-                        $this->rawNode->parentNode->replaceChild($newFrag, $this->rawNode);
-                        return $this->rawNode->parentNode;
+                        $parent = $this->rawNode->parentNode;
+                        $parent->replaceChild($newFrag, $this->rawNode);
+                        return $parent;
                         break;
                     default:
                         return $decrypted;
@@ -1373,6 +1528,14 @@ class XMLSecEnc {
         }
         $cipherData = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherData'));
         $cipherData->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherValue', $strEncKey));
+        if (is_array($this->references) && count($this->references) > 0) {
+           $refList =  $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:ReferenceList'));
+            foreach ($this->references AS $name=>$reference) {
+                $refuri = $reference["refuri"];
+                $dataRef = $refList->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:DataReference'));
+                $dataRef->setAttribute("URI", '#' . $refuri);
+            }
+        }
         return;
     }
 
@@ -1430,74 +1593,88 @@ class XMLSecEnc {
         if (empty($node) || (! $node instanceof DOMNode)) {
             return NULL;
         }
-        if ($doc = $node->ownerDocument) {
-            $xpath = new DOMXPath($doc);
-            $xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS);
-            $xpath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS);
-            $query = "./xmlsecdsig:KeyInfo";
-            $nodeset = $xpath->query($query, $node);
-            if ($encmeth = $nodeset->item(0)) {
-                foreach ($encmeth->childNodes AS $child) {
-                    switch ($child->localName) {
-                        case 'KeyName':
-                            if (! empty($objBaseKey)) {
-                                $objBaseKey->name = $child->nodeValue;
-                            }
-                            break;
-                        case 'KeyValue':
-                            foreach ($child->childNodes AS $keyval) {
-                                switch ($keyval->localName) {
-                                    case 'DSAKeyValue':
-                                        throw new Exception("DSAKeyValue currently not supported");
-                                        break;
-                                    case 'RSAKeyValue':
-                                        $modulus = NULL;
-                                        $exponent = NULL;
-                                        if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) {
-                                            $modulus = base64_decode($modulusNode->nodeValue);
-                                        }
-                                        if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) {
-                                            $exponent = base64_decode($exponentNode->nodeValue);
-                                        }
-                                        if (empty($modulus) || empty($exponent)) {
-                                            throw new Exception("Missing Modulus or Exponent");
-                                        }
-                                        $publicKey = XMLSecurityKey::convertRSA($modulus, $exponent);
-                                        $objBaseKey->loadKey($publicKey);
-                                        break;
+        $doc = $node->ownerDocument;
+        if (!$doc) {
+            return NULL;
+        }
+
+        $xpath = new DOMXPath($doc);
+        $xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS);
+        $xpath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS);
+        $query = "./xmlsecdsig:KeyInfo";
+        $nodeset = $xpath->query($query, $node);
+        $encmeth = $nodeset->item(0);
+        if (!$encmeth) {
+            /* No KeyInfo in EncryptedData / EncryptedKey. */
+            return $objBaseKey;
+        }
+
+        foreach ($encmeth->childNodes AS $child) {
+            switch ($child->localName) {
+                case 'KeyName':
+                    if (! empty($objBaseKey)) {
+                        $objBaseKey->name = $child->nodeValue;
+                    }
+                    break;
+                case 'KeyValue':
+                    foreach ($child->childNodes AS $keyval) {
+                        switch ($keyval->localName) {
+                            case 'DSAKeyValue':
+                                throw new Exception("DSAKeyValue currently not supported");
+                                break;
+                            case 'RSAKeyValue':
+                                $modulus = NULL;
+                                $exponent = NULL;
+                                if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) {
+                                    $modulus = base64_decode($modulusNode->nodeValue);
                                 }
-                            }
-                            break;
-                        case 'RetrievalMethod':
-                            /* Not currently supported */
-                            break;
-                        case 'EncryptedKey':
-                            $objenc = new XMLSecEnc();
-                            $objenc->setNode($child);
-                            if (! $objKey = $objenc->locateKey()) {
-                                throw new Exception("Unable to locate algorithm for this Encrypted Key");
-                            }
-                            $objKey->isEncrypted = TRUE;
-                            $objKey->encryptedCtx = $objenc;
-                            XMLSecEnc::staticLocateKeyInfo($objKey, $child);
-                            return $objKey;
-                            break;
-                        case 'X509Data':
-                            if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) {
-                                if ($x509certNodes->length > 0) {
-                                    $x509cert = $x509certNodes->item(0)->textContent;
-                                    $x509cert = str_replace(array("\r", "\n"), "", $x509cert);
-                                    $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
-                                    $objBaseKey->loadKey($x509cert, FALSE, TRUE);
+                                if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) {
+                                    $exponent = base64_decode($exponentNode->nodeValue);
                                 }
-                            }
-                            break;
+                                if (empty($modulus) || empty($exponent)) {
+                                    throw new Exception("Missing Modulus or Exponent");
+                                }
+                                $publicKey = XMLSecurityKey::convertRSA($modulus, $exponent);
+                                $objBaseKey->loadKey($publicKey);
+                                break;
+                        }
                     }
-                }
+                    break;
+                case 'RetrievalMethod':
+                    $type = $child->getAttribute('Type');
+                    if ($type !== 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') {
+                        /* Unsupported key type. */
+                        break;
+                    }
+                    $uri = $child->getAttribute('URI');
+                    if ($uri[0] !== '#') {
+                        /* URI not a reference - unsupported. */
+                        break;
+                    }
+                    $id = substr($uri, 1);
+
+                    $query = "//xmlsecenc:EncryptedKey[@Id='$id']";
+                    $keyElement = $xpath->query($query)->item(0);
+                    if (!$keyElement) {
+                        throw new Exception("Unable to locate EncryptedKey with @Id='$id'.");
+                    }
+
+                    return XMLSecurityKey::fromEncryptedKeyElement($keyElement);
+                case 'EncryptedKey':
+                    return XMLSecurityKey::fromEncryptedKeyElement($child);
+                case 'X509Data':
+                    if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) {
+                        if ($x509certNodes->length > 0) {
+                            $x509cert = $x509certNodes->item(0)->textContent;
+                            $x509cert = str_replace(array("\r", "\n"), "", $x509cert);
+                            $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
+                            $objBaseKey->loadKey($x509cert, FALSE, TRUE);
+                        }
+                    }
+                    break;
             }
-            return $objBaseKey;
         }
-        return NULL;
+        return $objBaseKey;
     }
 
     public function locateKeyInfo($objBaseKey=NULL, $node=NULL) {
@@ -1507,4 +1684,3 @@ class XMLSecEnc {
         return XMLSecEnc::staticLocateKeyInfo($objBaseKey, $node);
     }
 }
-?>
\ No newline at end of file