public function decryptSoapDoc($doc, $options) { $privKey = null; $privKey_isFile = false; $privKey_isCert = false; if (is_array($options)) { $privKey = !empty($options["keys"]["private"]["key"]) ? $options["keys"]["private"]["key"] : null; $privKey_isFile = !empty($options["keys"]["private"]["isFile"]) ? true : false; $privKey_isCert = !empty($options["keys"]["private"]["isCert"]) ? true : false; } $objenc = new XMLSecEnc(); $xpath = new DOMXPath($doc); $envns = $doc->documentElement->namespaceURI; $xpath->registerNamespace("soapns", $envns); $xpath->registerNamespace("soapenc", "http://www.w3.org/2001/04/xmlenc#"); $nodes = $xpath->query('/soapns:Envelope/soapns:Header/*[local-name()="Security"]/soapenc:EncryptedKey'); $references = array(); if ($node = $nodes->item(0)) { $objenc = new XMLSecEnc(); $objenc->setNode($node); if (!($objKey = $objenc->locateKey())) { throw new Exception("Unable to locate algorithm for this Encrypted Key"); } $objKey->isEncrypted = true; $objKey->encryptedCtx = $objenc; XMLSecEnc::staticLocateKeyInfo($objKey, $node); if ($objKey && $objKey->isEncrypted) { $objencKey = $objKey->encryptedCtx; $objKey->loadKey($privKey, $privKey_isFile, $privKey_isCert); $key = $objencKey->decryptKey($objKey); $objKey->loadKey($key); } $refnodes = $xpath->query('./soapenc:ReferenceList/soapenc:DataReference/@URI', $node); foreach ($refnodes as $reference) { $references[] = $reference->nodeValue; } } foreach ($references as $reference) { $arUrl = parse_url($reference); $reference = $arUrl['fragment']; $query = '//*[@Id="' . $reference . '"]'; $nodes = $xpath->query($query); $encData = $nodes->item(0); if ($algo = $xpath->evaluate("string(./soapenc:EncryptionMethod/@Algorithm)", $encData)) { $objKey = new XMLSecurityKey($algo); $objKey->loadKey($key); } $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); $decrypt = $objenc->decryptNode($objKey, true); } return true; }
static function staticLocateKeyInfo($objBaseKey = NULL, $node = NULL) { 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; } } 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); } } break; } } } return $objBaseKey; } return NULL; }
/** * 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; }
/** * Decrypts an encrypted element. * * @param DOMElement $encryptedData The encrypted data. * @param XMLSecurityKey $inputKey The decryption key. * * @return DOMElement The decrypted element. */ public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey) { $enc = new XMLSecEnc(); $enc->setNode($encryptedData); $enc->type = $encryptedData->getAttribute("Type"); $symmetricKey = $enc->locateKey($encryptedData); if (!$symmetricKey) { throw new Exception('Could not locate key algorithm in encrypted data.'); } $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey); if (!$symmetricKeyInfo) { throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.'); } $inputKeyAlgo = $inputKey->getAlgorith(); if ($symmetricKeyInfo->isEncrypted) { $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith(); if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) { $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P; } if ($inputKeyAlgo !== $symKeyInfoAlgo) { throw new Exception('Algorithm mismatch between input key and key used to encrypt ' . ' the symmetric key for the message. Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' . var_export($symKeyInfoAlgo, true)); } $encKey = $symmetricKeyInfo->encryptedCtx; $symmetricKeyInfo->key = $inputKey->key; $keySize = $symmetricKey->getSymmetricKeySize(); if ($keySize === null) { // To protect against "key oracle" attacks throw new Exception('Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, true)); } $key = $encKey->decryptKey($symmetricKeyInfo); if (strlen($key) != $keySize) { $encryptedKey = $encKey->getCipherValue(); $pkey = openssl_pkey_get_details($symmetricKeyInfo->key); $pkey = sha1(serialize($pkey), true); $key = sha1($encryptedKey . $pkey, true); /* Make sure that the key has the correct length. */ if (strlen($key) > $keySize) { $key = substr($key, 0, $keySize); } elseif (strlen($key) < $keySize) { $key = str_pad($key, $keySize); } } $symmetricKey->loadkey($key); } else { $symKeyAlgo = $symmetricKey->getAlgorith(); if ($inputKeyAlgo !== $symKeyAlgo) { throw new Exception('Algorithm mismatch between input key and key in message. ' . 'Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' . var_export($symKeyAlgo, true)); } $symmetricKey = $inputKey; } $decrypted = $enc->decryptNode($symmetricKey, false); $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $decrypted . '</root>'; $newDoc = new DOMDocument(); $newDoc->preserveWhiteSpace = false; $newDoc->formatOutput = true; $newDoc = self::loadXML($newDoc, $xml); if (!$newDoc) { throw new Exception('Failed to parse decrypted XML.'); } $decryptedElement = $newDoc->firstChild->firstChild; if ($decryptedElement === null) { throw new Exception('Missing encrypted element.'); } return $decryptedElement; }
/** * Decrypts an encrypted element. * * @param DOMElement $encryptedData The encrypted data. * @param XMLSecurityKey $inputKey The decryption key. * * @return DOMElement The decrypted element. */ public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey) { $enc = new XMLSecEnc(); $enc->setNode($encryptedData); $enc->type = $encryptedData->getAttribute("Type"); $symmetricKey = $enc->locateKey($encryptedData); if (!$symmetricKey) { throw new Exception('Could not locate key algorithm in encrypted data.'); } $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey); if (!$symmetricKeyInfo) { throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.'); } $inputKeyAlgo = $inputKey->getAlgorith(); if ($symmetricKeyInfo->isEncrypted) { $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith(); if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) { $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P; } if ($inputKeyAlgo !== $symKeyInfoAlgo) { throw new Exception('Algorithm mismatch between input key and key used to encrypt ' . ' the symmetric key for the message. Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' . var_export($symKeyInfoAlgo, true)); } $encKey = $symmetricKeyInfo->encryptedCtx; $symmetricKeyInfo->key = $inputKey->key; $key = $encKey->decryptKey($symmetricKeyInfo); $symmetricKey->loadkey($key); } else { $symKeyAlgo = $symmetricKey->getAlgorith(); if ($inputKeyAlgo !== $symKeyAlgo) { throw new Exception('Algorithm mismatch between input key and key in message. ' . 'Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' . var_export($symKeyAlgo, true)); } $symmetricKey = $inputKey; } $decrypted = $enc->decryptNode($symmetricKey, false); $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $decrypted . '</root>'; $newDoc = new DOMDocument(); $newDoc = self::loadXML($newDoc, $xml); if (!$newDoc) { throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?'); } $decryptedElement = $newDoc->firstChild->firstChild; if ($decryptedElement === null) { throw new Exception('Missing encrypted element.'); } return $decryptedElement; }
/** * Decrypt an encrypted element. * * This is an internal helper function. * * @param DOMElement $encryptedData The encrypted data. * @param XMLSecurityKey $inputKey The decryption key. * @param array &$blacklist Blacklisted decryption algorithms. * @return DOMElement The decrypted element. * @throws Exception */ private static function doDecryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey, array &$blacklist) { $enc = new XMLSecEnc(); $enc->setNode($encryptedData); $enc->type = $encryptedData->getAttribute("Type"); $symmetricKey = $enc->locateKey($encryptedData); if (!$symmetricKey) { throw new Exception('Could not locate key algorithm in encrypted data.'); } $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey); if (!$symmetricKeyInfo) { throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.'); } $inputKeyAlgo = $inputKey->getAlgorith(); if ($symmetricKeyInfo->isEncrypted) { $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith(); if (in_array($symKeyInfoAlgo, $blacklist, TRUE)) { throw new Exception('Algorithm disabled: ' . var_export($symKeyInfoAlgo, TRUE)); } if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) { /* * The RSA key formats are equal, so loading an RSA_1_5 key * into an RSA_OAEP_MGF1P key can be done without problems. * We therefore pretend that the input key is an * RSA_OAEP_MGF1P key. */ $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P; } /* Make sure that the input key format is the same as the one used to encrypt the key. */ if ($inputKeyAlgo !== $symKeyInfoAlgo) { throw new Exception('Algorithm mismatch between input key and key used to encrypt ' . ' the symmetric key for the message. Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' . var_export($symKeyInfoAlgo, TRUE)); } /** @var XMLSecEnc $encKey */ $encKey = $symmetricKeyInfo->encryptedCtx; $symmetricKeyInfo->key = $inputKey->key; $keySize = $symmetricKey->getSymmetricKeySize(); if ($keySize === NULL) { /* To protect against "key oracle" attacks, we need to be able to create a * symmetric key, and for that we need to know the key size. */ throw new Exception('Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, TRUE)); } try { $key = $encKey->decryptKey($symmetricKeyInfo); if (strlen($key) != $keySize) { throw new Exception('Unexpected key size (' . strlen($key) * 8 . 'bits) for encryption algorithm: ' . var_export($symmetricKey->type, TRUE)); } } catch (Exception $e) { /* We failed to decrypt this key. Log it, and substitute a "random" key. */ SAML2_Utils::getContainer()->getLogger()->error('Failed to decrypt symmetric key: ' . $e->getMessage()); /* Create a replacement key, so that it looks like we fail in the same way as if the key was correctly padded. */ /* We base the symmetric key on the encrypted key and private key, so that we always behave the * same way for a given input key. */ $encryptedKey = $encKey->getCipherValue(); $pkey = openssl_pkey_get_details($symmetricKeyInfo->key); $pkey = sha1(serialize($pkey), TRUE); $key = sha1($encryptedKey . $pkey, TRUE); /* Make sure that the key has the correct length. */ if (strlen($key) > $keySize) { $key = substr($key, 0, $keySize); } elseif (strlen($key) < $keySize) { $key = str_pad($key, $keySize); } } $symmetricKey->loadkey($key); } else { $symKeyAlgo = $symmetricKey->getAlgorith(); /* Make sure that the input key has the correct format. */ if ($inputKeyAlgo !== $symKeyAlgo) { throw new Exception('Algorithm mismatch between input key and key in message. ' . 'Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' . var_export($symKeyAlgo, TRUE)); } $symmetricKey = $inputKey; } $algorithm = $symmetricKey->getAlgorith(); if (in_array($algorithm, $blacklist, TRUE)) { throw new Exception('Algorithm disabled: ' . var_export($algorithm, TRUE)); } /** @var string $decrypted */ $decrypted = $enc->decryptNode($symmetricKey, FALSE); /* * This is a workaround for the case where only a subset of the XML * tree was serialized for encryption. In that case, we may miss the * namespaces needed to parse the XML. */ $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ' . 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $decrypted . '</root>'; $newDoc = new DOMDocument(); if (!@$newDoc->loadXML($xml)) { throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?'); } $decryptedElement = $newDoc->firstChild->firstChild; if ($decryptedElement === NULL) { throw new Exception('Missing encrypted element.'); } if (!$decryptedElement instanceof DOMElement) { throw new Exception('Decrypted element was not actually a DOMElement.'); } return $decryptedElement; }
/** * Decrypts the Assertion (DOMDocument) * * @param string $dom DomDocument * * @throws Exception * @return DOMDocument Decrypted Assertion */ private function _decryptAssertion($dom) { $pem = $this->_settings->getSPkey(); if (empty($pem)) { throw new Exception("No private key available, check settings"); } $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($dom); if (!$encData) { throw new Exception("Cannot locate encrypted assertion"); } $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); if (!($objKey = $objenc->locateKey())) { throw new Exception("Unknown algorithm"); } $key = null; if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { if ($objKeyInfo->isEncrypted) { $objencKey = $objKeyInfo->encryptedCtx; $objKeyInfo->loadKey($pem, false, false); $key = $objencKey->decryptKey($objKeyInfo); } } if (empty($objKey->key)) { $objKey->loadKey($key); } $decrypt = $objenc->decryptNode($objKey, true); if ($decrypt instanceof DOMDocument) { return $decrypt; } else { return $decrypt->ownerDocument; } }
/** * Decrypt an encrypted element. * * @param DOMElement $encryptedData The encrypted data. * @param XMLSecurityKey $inputKey The decryption key. * @return DOMElement The decrypted element. */ public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey) { $enc = new XMLSecEnc(); $enc->setNode($encryptedData); $enc->type = $encryptedData->getAttribute("Type"); $symmetricKey = $enc->locateKey($encryptedData); if (!$symmetricKey) { throw new Exception('Could not locate key algorithm in encrypted data.'); } $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey); if (!$symmetricKeyInfo) { throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.'); } $inputKeyAlgo = $inputKey->getAlgorith(); if ($symmetricKeyInfo->isEncrypted) { $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith(); if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) { /* * The RSA key formats are equal, so loading an RSA_1_5 key * into an RSA_OAEP_MGF1P key can be done without problems. * We therefore pretend that the input key is an * RSA_OAEP_MGF1P key. */ $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P; } /* Make sure that the input key format is the same as the one used to encrypt the key. */ if ($inputKeyAlgo !== $symKeyInfoAlgo) { throw new Exception('Algorithm mismatch between input key and key used to encrypt ' . ' the symmetric key for the message. Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' . var_export($symKeyInfoAlgo, TRUE)); } $encKey = $symmetricKeyInfo->encryptedCtx; $symmetricKeyInfo->key = $inputKey->key; $key = $encKey->decryptKey($symmetricKeyInfo); $symmetricKey->loadkey($key); } else { $symKeyAlgo = $symmetricKey->getAlgorith(); /* Make sure that the input key has the correct format. */ if ($inputKeyAlgo !== $symKeyAlgo) { throw new Exception('Algorithm mismatch between input key and key in message. ' . 'Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' . var_export($symKeyAlgo, TRUE)); } $symmetricKey = $inputKey; } $decrypted = $enc->decryptNode($symmetricKey, FALSE); /* * This is a workaround for the case where only a subset of the XML * tree was serialized for encryption. In that case, we may miss the * namespaces needed to parse the XML. */ $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $decrypted . '</root>'; $newDoc = new DOMDocument(); if (!$newDoc->loadXML($xml)) { throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?'); } $decryptedElement = $newDoc->firstChild->firstChild; if ($decryptedElement === NULL) { throw new Exception('Missing encrypted element.'); } return $decryptedElement; }
/** * This function decrypts the Assertion in the AuthnResponse * It throws an exception if the encryptAssertion for the remote idp is true and * the assertion is not encrypted * To Do: handle multible assertions */ private function decryptAssertion() { $dom = $this->getDOM(); $encryptedassertion = $this->doXPathQuery('/samlp:Response/saml:EncryptedAssertion')->item(0); $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($dom); if ($encData) { $spmd = $this->metadata->getMetaDataCurrent('saml20-sp-hosted'); $spid = $this->metadata->getMetaDataCurrentEntityID('saml20-sp-hosted'); $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); $key = NULL; $objKey = $objenc->locateKey($encData); if ($objKey) { if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { if ($objKeyInfo->isEncrypted) { $objencKey = $objKeyInfo->encryptedCtx; if (empty($spmd['privatekey'])) { throw new Exception("SAML: RSA private key not configured. This is required to decrypt the response. saml20-sp-hosted: {$spid}"); } $objKeyInfo->loadKey($spmd['privatekey']); $key = $objencKey->decryptKey($objKeyInfo); } else { $idpmd = $this->metadata->getMetaData($this->issuer, 'saml20-idp-remote'); if (!isset($idpmd['sharedkey'])) { throw new Exception("Shared key for decrypting assertion needed, but not specified for saml20-idp-remote id: " . $this->issuer); } $key = $idpmd['sharedkey']; } } } if (empty($objKey) || empty($key)) { throw new Exception("Error loading key to handle Decryption: >" . var_export($objKey, true)); } $objKey->loadkey($key); $decrypted = $objenc->decryptNode($objKey, false); $newdoc = new DOMDocument(); $newdoc->loadXML('<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $decrypted . '</root>'); $importEnc = $encData->ownerDocument->importNode($newdoc->documentElement->firstChild, TRUE); $encryptedassertion->parentNode->replaceChild($importEnc, $encryptedassertion); } else { $md = $this->metadata->getMetaData($this->issuer, 'saml20-idp-remote'); if (isset($md['assertion.encryption']) && $md['assertion.encryption']) { throw new Exception('Received unencrypted assertion from [' . $this->issuer . '] contrary to its metadata attribute [assertion.encryption]: ' . $md['assertion.encryption']); } } }
/** * Decrypts the Assertion (DOMDocument) * * @param DomNode $dom DomDocument * * @return DOMDocument Decrypted Assertion * * @throws Exception */ protected function _decryptAssertion($dom) { $pem = $this->_settings->getSPkey(); if (empty($pem)) { throw new Exception("No private key available, check settings"); } $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($dom); if (!$encData) { throw new Exception("Cannot locate encrypted assertion"); } $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); if (!($objKey = $objenc->locateKey())) { throw new Exception("Unknown algorithm"); } $key = null; if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { if ($objKeyInfo->isEncrypted) { $objencKey = $objKeyInfo->encryptedCtx; $objKeyInfo->loadKey($pem, false, false); $key = $objencKey->decryptKey($objKeyInfo); } else { // symmetric encryption key support $objKeyInfo->loadKey($pem, false, false); } } if (empty($objKey->key)) { $objKey->loadKey($key); } $decrypted = $objenc->decryptNode($objKey, true); if ($decrypted instanceof DOMDocument) { return $decrypted; } else { $encryptedAssertion = $decrypted->parentNode; $container = $encryptedAssertion->parentNode; # Fix possible issue with saml namespace if (!$decrypted->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml') && !$decrypted->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml2') && !$decrypted->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns') && !$container->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml') && !$container->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml2')) { if (strpos($encryptedAssertion->tagName, 'saml2:') !== false) { $ns = 'xmlns:saml2'; } else { if (strpos($encryptedAssertion->tagName, 'saml:') != false) { $ns = 'xmlns:saml'; } else { $ns = 'xmlns'; } } $decrypted->setAttributeNS('http://www.w3.org/2000/xmlns/', $ns, OneLogin_Saml2_Constants::NS_SAML); } $container->replaceChild($decrypted, $encryptedAssertion); return $decrypted->ownerDocument; } }
/** * * @@dataProvider decryptFilesProvider * @throws \Exception */ public function testDecrypt($testName, $testFile, $privKey) { $doc = new \DOMDocument(); $output = null; $doc->load($testFile); $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($doc); $this->assertInstanceOf('\\DOMElement', $encData, "Cannot locate Encrypted Data"); $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); $objKey = $objenc->locateKey(); $this->assertInstanceOf('\\XmlSecLibs\\XMLSecurityKey', $objKey, "We know the secret key, but not the algorithm"); $key = null; if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { if ($objKeyInfo->isEncrypted) { $objencKey = $objKeyInfo->encryptedCtx; $objKeyInfo->loadKey($privKey, true); $key = $objencKey->decryptKey($objKeyInfo); } } if (!$objKey->key && empty($key)) { $objKeyInfo->loadKey($privKey, true); } if (empty($objKey->key)) { $objKey->loadKey($key); } $token = null; if ($decrypt = $objenc->decryptNode($objKey, true)) { $output = null; if ($decrypt instanceof \DOMNode) { if ($decrypt instanceof \DOMDocument) { $output = $decrypt->saveXML(); } else { $output = $decrypt->ownerDocument->saveXML(); } } else { $output = $decrypt; } } $outfile = dirname(__FILE__) . "/../basic-doc.xml"; $res = null; $this->assertFileExists($outfile); $resDoc = new \DOMDocument(); $resDoc->load($outfile); $res = $resDoc->saveXML(); $this->assertEquals($res, $output, "{$testName} Failed to decrypt {$testFile}"); }