diff --git a/lib/SAML2/Utils.php b/lib/SAML2/Utils.php index fe83f12ab607ef60b74a5e4994cae50f704edc9c..156ab941eb82f2c1dd15215ee2bd890500a6d644 100644 --- a/lib/SAML2/Utils.php +++ b/lib/SAML2/Utils.php @@ -239,6 +239,89 @@ class SAML2_Utils { $objXMLSecDSig->insertSignature($root, $insertBefore); } + + + /** + * 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; + } + } ?> \ No newline at end of file