/** * 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; } }
/** * 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; } }
/** * 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']); } } }
/** * * @@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}"); }