/** * Set the assertion. * * @param SAML2_Assertion $assertion The assertion. * @param XMLSecurityKey $key The key we should use to encrypt the assertion. * @throws Exception */ public function setAssertion(SAML2_Assertion $assertion, XMLSecurityKey $key) { $xml = $assertion->toXML(); SAML2_Utils::getContainer()->debugMessage($xml, 'encrypt'); $enc = new XMLSecEnc(); $enc->setNode($xml); $enc->type = XMLSecEnc::Element; switch ($key->type) { case XMLSecurityKey::TRIPLEDES_CBC: case XMLSecurityKey::AES128_CBC: case XMLSecurityKey::AES192_CBC: case XMLSecurityKey::AES256_CBC: $symmetricKey = $key; break; case XMLSecurityKey::RSA_1_5: case XMLSecurityKey::RSA_OAEP_MGF1P: $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); $symmetricKey->generateSessionKey(); $enc->encryptKey($key, $symmetricKey); break; default: throw new Exception('Unknown key type for encryption: ' . $key->type); } $this->encryptedData = $enc->encryptNode($symmetricKey); }
/** * Add an EncryptedAttribute Statement-node to the assertion. * * @param DOMElement $root The assertion element we should add the Encrypted Attribute Statement to. */ private function addEncryptedAttributeStatement(DOMElement $root) { if ($this->requiredEncAttributes == FALSE) { return; } $document = $root->ownerDocument; $attributeStatement = $document->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeStatement'); $root->appendChild($attributeStatement); foreach ($this->attributes as $name => $values) { $document2 = new DOMDocument(); $attribute = $document2->createElementNS(SAML2_Const::NS_SAML, 'saml:Attribute'); $attribute->setAttribute('Name', $name); $document2->appendChild($attribute); if ($this->nameFormat !== SAML2_Const::NAMEFORMAT_UNSPECIFIED) { $attribute->setAttribute('NameFormat', $this->nameFormat); } foreach ($values as $value) { if (is_string($value)) { $type = 'xs:string'; } elseif (is_int($value)) { $type = 'xs:integer'; } else { $type = NULL; } $attributeValue = $document2->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeValue'); $attribute->appendChild($attributeValue); if ($type !== NULL) { $attributeValue->setAttributeNS(SAML2_Const::NS_XSI, 'xsi:type', $type); } if ($value instanceof DOMNodeList) { for ($i = 0; $i < $value->length; $i++) { $node = $document2->importNode($value->item($i), TRUE); $attributeValue->appendChild($node); } } else { $attributeValue->appendChild($document2->createTextNode($value)); } } /*Once the attribute nodes are built, the are encrypted*/ $EncAssert = new XMLSecEnc(); $EncAssert->setNode($document2->documentElement); $EncAssert->type = 'http://www.w3.org/2001/04/xmlenc#Element'; /* * Attributes are encrypted with a session key and this one with * $EncryptionKey */ $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $symmetricKey->generateSessionKey(); $EncAssert->encryptKey($this->encryptionKey, $symmetricKey); $EncrNode = $EncAssert->encryptNode($symmetricKey); $EncAttribute = $document->createElementNS(SAML2_Const::NS_SAML, 'saml:EncryptedAttribute'); $attributeStatement->appendChild($EncAttribute); $n = $document->importNode($EncrNode, true); $EncAttribute->appendChild($n); } }
public function encryptSoapDoc($siteKey, $objKey, $options = null, $encryptSignature = true) { $enc = new XMLSecEnc(); $xpath = new DOMXPath($this->envelope->ownerDocument); if ($encryptSignature == false) { $nodes = $xpath->query('//*[local-name()="Body"]'); } else { $nodes = $xpath->query('//*[local-name()="Signature"] | //*[local-name()="Body"]'); } foreach ($nodes as $node) { $type = XMLSecEnc::Element; $name = $node->localName; if ($name == "Body") { $type = XMLSecEnc::Content; } $enc->addReference($name, $node, $type); } $enc->encryptReferences($objKey); $enc->encryptKey($siteKey, $objKey, false); $nodes = $xpath->query('//*[local-name()="Security"]'); $signode = $nodes->item(0); $this->addEncryptedKey($signode, $enc, $siteKey, $options); }
/** * Generates a nameID. * * @param string $value fingerprint * @param string $spnq SP Name Qualifier * @param string $format SP Format * @param string $cert IdP Public cert to encrypt the nameID * * @return string $nameIDElement DOMElement | XMLSec nameID */ public static function generateNameId($value, $spnq, $format, $cert = null) { $doc = new DOMDocument(); $nameId = $doc->createElement('saml:NameID'); $nameId->setAttribute('SPNameQualifier', $spnq); $nameId->setAttribute('Format', $format); $nameId->appendChild($doc->createTextNode($value)); $doc->appendChild($nameId); if (!empty($cert)) { $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'public')); $seckey->loadKey($cert); $enc = new XMLSecEnc(); $enc->setNode($nameId); $enc->type = XMLSecEnc::Element; $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); $symmetricKey->generateSessionKey(); $enc->encryptKey($seckey, $symmetricKey); $encryptedData = $enc->encryptNode($symmetricKey); $newdoc = new DOMDocument(); $encryptedID = $newdoc->createElement('saml:EncryptedID'); $newdoc->appendChild($encryptedID); $encryptedID->appendChild($encryptedID->ownerDocument->importNode($encryptedData, true)); return $newdoc->saveXML($encryptedID); } else { return $doc->saveXML($nameId); } }
public function EncryptBody($siteKey, $objKey, $token) { $enc = new XMLSecEnc(); foreach ($this->envelope->childNodes as $node) { if ($node->namespaceURI == $this->soapNS && $node->localName == 'Body') { break; } } $enc->setNode($node); /* encrypt the symmetric key */ $enc->encryptKey($siteKey, $objKey, FALSE); $enc->type = XMLSecEnc::Content; /* Using the symmetric key to actually encrypt the data */ $encNode = $enc->encryptNode($objKey); $guid = XMLSecurityDSig::generate_GUID(); $encNode->setAttribute('Id', $guid); $refNode = $encNode->firstChild; while ($refNode && $refNode->nodeType != XML_ELEMENT_NODE) { $refNode = $refNode->nextSibling; } if ($refNode) { $refNode = $refNode->nextSibling; } if ($this->addEncryptedKey($encNode, $enc, $token)) { $this->AddReference($enc->encKey, $guid); } }
/** * Encrypt the NameID in the LogoutRequest. * * @param XMLSecurityKey $key The encryption key. */ public function encryptNameId(XMLSecurityKey $key) { /* First create a XML representation of the NameID. */ $doc = new DOMDocument(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $this->nameId); $nameId = $root->firstChild; SAML2_Utils::getContainer()->debugMessage($nameId, 'encrypt'); /* Encrypt the NameID. */ $enc = new XMLSecEnc(); $enc->setNode($nameId); $enc->type = XMLSecEnc::Element; $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); $symmetricKey->generateSessionKey(); $enc->encryptKey($key, $symmetricKey); $this->encryptedNameId = $enc->encryptNode($symmetricKey); $this->nameId = NULL; }
/** * @throws \Exception */ public function testEncryptNoReplace() { $dom = new \DOMDocument(); $dom->load(dirname(__FILE__) . '/../basic-doc.xml'); $origData = $dom->saveXML(); $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $objKey->generateSessionKey(); $siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public')); $siteKey->loadKey(dirname(__FILE__) . '/../mycert.pem', true, true); $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); $enc->encryptKey($siteKey, $objKey); $enc->type = XMLSecEnc::Element; $encNode = $enc->encryptNode($objKey, false); $newData = $dom->saveXML(); $this->assertEquals($origData, $newData, "Original data was modified"); $this->assertFalse($encNode->namespaceURI !== XMLSecEnc::XMLENCNS || $encNode->localName !== 'EncryptedData', "Encrypted node wasn't a <xenc:EncryptedData>-element"); }
public function sendResponse($response, $idmetaindex, $spentityid, $relayState = null) { $idpmd = $this->metadata->getMetaData($idmetaindex, 'saml20-idp-hosted'); $spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote'); $destination = $spmd['AssertionConsumerService']; if (empty($idpmd['privatekey'])) { throw new Exception('SAML: RSA private key not configured. This is required to sign the authentication response.'); } if (empty($idpmd['certificate'])) { throw new Exception('SAML: X.509 certificate not configured. This is required to attach to the authentication response.'); } // XMLDSig. Sign the complete request with the key stored in cert/server.pem $objXMLSecDSig = new XMLSecurityDSig(); $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); try { $responsedom = new DOMDocument(); $responsedom->loadXML(str_replace("\n", "", str_replace("\r", "", $response))); } catch (Exception $e) { throw new Exception("foo"); } $responseroot = $responsedom->getElementsByTagName('Response')->item(0); $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0); /* Determine what we should sign - either the Response element or the Assertion. The default * is to sign the Assertion, but that can be overridden by the 'signresponse' option in the * SP metadata or 'saml20.signresponse' in the global configuration. */ $signResponse = FALSE; if (array_key_exists('signresponse', $spmd) && $spmd['signresponse'] !== NULL) { $signResponse = $spmd['signresponse']; if (!is_bool($signResponse)) { throw new Exception('Expected the \'signresponse\' option in the metadata of the' . ' SP \'' . $spmd['entityid'] . '\' to be a boolean value.'); } } else { $signResponse = $this->configuration->getBoolean('saml20.signresponse', FALSE); } if ($signResponse) { // Sign the response. $objXMLSecDSig->addReferenceList(array($responseroot), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), array('id_name' => 'ID')); } else { // Sign the assertion. $objXMLSecDSig->addReferenceList(array($firstassertionroot), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), array('id_name' => 'ID')); } $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private')); if (array_key_exists('privatekey_pass', $idpmd)) { $objKey->passphrase = $idpmd['privatekey_pass']; } $objKey->loadKey($idpmd['privatekey']); $objXMLSecDSig->sign($objKey); $objXMLSecDSig->add509Cert($idpmd['certificate'], true); if ($signResponse) { $objXMLSecDSig->appendSignature($responseroot, true, false); } else { $objXMLSecDSig->appendSignature($firstassertionroot, true, true); } if (isset($spmd['assertion.encryption']) && $spmd['assertion.encryption']) { $encryptedassertion = $responsedom->createElement("saml:EncryptedAssertion"); $encryptedassertion->setAttribute("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion"); $firstassertionroot->parentNode->replaceChild($encryptedassertion, $firstassertionroot); $encryptedassertion->appendChild($firstassertionroot); $enc = new XMLSecEnc(); $enc->setNode($firstassertionroot); $enc->type = XMLSecEnc::Element; $objKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); if (isset($spmd['sharedkey'])) { $objKey->loadkey($spmd['sharedkey']); } else { $key = $objKey->generateSessionKey(); $objKey->loadKey($key); if (empty($spmd['certificate'])) { throw new Exception("Public key for encrypting assertion needed, but not specified for saml20-sp-remote id: " . $spentityid); } $keyKey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'public')); $keyKey->loadKey($spmd['certificate']); $enc->encryptKey($keyKey, $objKey); } $encNode = $enc->encryptNode($objKey); # replacing the unencrypted node } $response = $responsedom->saveXML(); SimpleSAML_Utilities::validateXMLDocument($response, 'saml20'); # openssl genrsa -des3 -out server.key 1024 # openssl rsa -in server.key -out server.pem # openssl req -new -key server.key -out server.csr # openssl x509 -req -days 60 -in server.csr -signkey server.key -out server.crt if ($this->configuration->getValue('debug')) { $p = new SimpleSAML_XHTML_Template($this->configuration, 'post-debug.php'); $p->data['header'] = 'SAML Response Debug-mode'; $p->data['RelayStateName'] = 'RelayState'; $p->data['RelayState'] = $relayState; $p->data['destination'] = $destination; $p->data['response'] = str_replace("\n", "", base64_encode($response)); $p->data['responseHTML'] = htmlentities($responsedom->saveHTML()); $p->show(); } else { $p = new SimpleSAML_XHTML_Template($this->configuration, 'post.php'); $p->data['RelayStateName'] = 'RelayState'; $p->data['RelayState'] = $relayState; $p->data['destination'] = $destination; $p->data['response'] = base64_encode($response); $p->show(); } }