Copyright (c) 2007-2015, Robert Richards . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Robert Richards nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Author: Robert Richards (rrichards@cdatazone.org)
 /**
  * BC compatible version of the signature check
  *
  * @param \SAML2\SignedElement      $element
  * @param \SAML2\Certificate\X509[] $pemCandidates
  *
  * @throws \Exception
  *
  * @return bool
  */
 protected function validateElementWithKeys(SignedElement $element, $pemCandidates)
 {
     $lastException = null;
     foreach ($pemCandidates as $index => $candidateKey) {
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
         $key->loadKey($candidateKey->getCertificate());
         try {
             /*
              * Make sure that we have a valid signature on either the response or the assertion.
              */
             $result = $element->validate($key);
             if ($result) {
                 $this->logger->debug(sprintf('Validation with key "#%d" succeeded', $index));
                 return true;
             }
             $this->logger->debug(sprintf('Validation with key "#%d" failed without exception.', $index));
         } catch (\Exception $e) {
             $this->logger->debug(sprintf('Validation with key "#%d" failed with exception: %s', $index, $e->getMessage()));
             $lastException = $e;
         }
     }
     if ($lastException !== null) {
         throw $lastException;
     } else {
         return false;
     }
 }
Example #2
0
 function __doRequest($request, $location, $saction, $version)
 {
     $dom = new DOMDocument();
     $dom->loadXML($request);
     $objWSA = new WSASoap($dom);
     $objWSA->addAction($saction);
     $objWSA->addTo($location);
     $objWSA->addMessageID();
     $objWSA->addReplyTo();
     $dom = $objWSA->getDoc();
     $objWSSE = new WSSESoap($dom);
     /* Sign all headers to include signing the WS-Addressing headers */
     $objWSSE->signAllHeaders = true;
     $objWSSE->addTimestamp();
     /* create new XMLSec Key using RSA SHA-1 and type is private key */
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
     /* load the private key from file - last arg is bool if key in file (true) or is string (FALSE) */
     $objKey->loadKey(PRIVATE_KEY, true);
     /* Sign the message - also signs appropraite WS-Security items */
     $objWSSE->signSoapDoc($objKey);
     /* Add certificate (BinarySecurityToken) to the message and attach pointer to Signature */
     $token = $objWSSE->addBinaryToken(file_get_contents(CERT_FILE));
     $objWSSE->attachTokentoSig($token);
     $request = $objWSSE->saveXML();
     return parent::__doRequest($request, $location, $saction, $version);
 }
 /**
  * @param AbstractSamlModel $object
  * @param XMLSecurityKey    $key
  *
  * @return SerializationContext
  */
 public function encrypt(AbstractSamlModel $object, XMLSecurityKey $key)
 {
     $oldKey = $key;
     $key = new XMLSecurityKey($this->keyTransportEncryption, ['type' => 'public']);
     $key->loadKey($oldKey->key);
     $serializationContext = new SerializationContext();
     $object->serialize($serializationContext->getDocument(), $serializationContext);
     $enc = new XMLSecEnc();
     $enc->setNode($serializationContext->getDocument()->firstChild);
     $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_SHA1:
         case XMLSecurityKey::RSA_SHA256:
         case XMLSecurityKey::RSA_SHA384:
         case XMLSecurityKey::RSA_SHA512:
         case XMLSecurityKey::RSA_OAEP_MGF1P:
             $symmetricKey = new XMLSecurityKey($this->blockEncryptionAlgorithm);
             $symmetricKey->generateSessionKey();
             $enc->encryptKey($key, $symmetricKey);
             break;
         default:
             throw new LightSamlException(sprintf('Unknown key type for encryption: "%s"', $key->type));
     }
     $this->encryptedElement = $enc->encryptNode($symmetricKey);
     return $serializationContext;
 }
 public function __doRequest($request, $location, $saction, $version)
 {
     $doc = new DOMDocument('1.0');
     $doc->loadXML($request);
     $objWSSE = new WSSESoap($doc);
     /* add Timestamp with no expiration timestamp */
     $objWSSE->addTimestamp();
     /* create new XMLSec Key using AES256_CBC and type is private key */
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
     /* load the private key from file - last arg is bool if key in file (true) or is string (false) */
     $objKey->loadKey(PRIVATE_KEY, true);
     /* Sign the message - also signs appropiate WS-Security items */
     $options = array("insertBefore" => false);
     $objWSSE->signSoapDoc($objKey, $options);
     /* Add certificate (BinarySecurityToken) to the message */
     $token = $objWSSE->addBinaryToken(file_get_contents(CERT_FILE));
     /* Attach pointer to Signature */
     $objWSSE->attachTokentoSig($token);
     $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC);
     $objKey->generateSessionKey();
     $siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
     $siteKey->loadKey(SERVICE_CERT, true, true);
     $options = array("KeyInfo" => array("X509SubjectKeyIdentifier" => true));
     $objWSSE->encryptSoapDoc($siteKey, $objKey, $options);
     $retVal = parent::__doRequest($objWSSE->saveXML(), $location, $saction, $version);
     $doc = new DOMDocument();
     $doc->loadXML($retVal);
     $options = array("keys" => array("private" => array("key" => PRIVATE_KEY, "isFile" => true, "isCert" => false)));
     $objWSSE->decryptSoapDoc($doc, $options);
     return $doc->saveXML();
 }
Example #5
0
 /**
  * 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(Assertion $assertion, XMLSecurityKey $key)
 {
     $xml = $assertion->toXML();
     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);
 }
Example #6
0
 /**
  * @param \SAML2\Certificate\PrivateKey $privateKey
  *
  * @return XMLSecurityKey
  * @throws \Exception
  */
 private function convertPrivateKeyToRsaKey(PrivateKey $privateKey)
 {
     $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
     $passphrase = $privateKey->getPassphrase();
     if ($passphrase) {
         $key->passphrase = $passphrase;
     }
     $key->loadKey($privateKey->getKeyAsString());
     return $key;
 }
Example #7
0
 public function getXML($request)
 {
     $doc = new \DOMDocument('1.0');
     $doc->loadXML($request);
     $objWSSE = new WSSESoap($doc);
     $objWSSE->addTimestamp();
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']);
     $objKey->loadKey($this->key, TRUE);
     $objWSSE->signSoapDoc($objKey, ["algorithm" => XMLSecurityDSig::SHA256]);
     $token = $objWSSE->addBinaryToken(file_get_contents($this->cert));
     $objWSSE->attachTokentoSig($token);
     return $objWSSE->saveXML();
 }
 public static function handleLoginRequest(IPerson $Person)
 {
     try {
         $binding = Binding::getCurrentBinding();
     } catch (Exception $e) {
         return static::throwUnauthorizedError('Cannot obtain SAML2 binding');
     }
     $request = $binding->receive();
     // build response
     $response = new Response();
     $response->setInResponseTo($request->getId());
     $response->setRelayState($request->getRelayState());
     $response->setDestination($request->getAssertionConsumerServiceURL());
     // build assertion
     $assertion = new Assertion();
     $assertion->setIssuer(static::$issuer);
     $assertion->setSessionIndex(ContainerSingleton::getInstance()->generateId());
     $assertion->setNotBefore(time() - 30);
     $assertion->setNotOnOrAfter(time() + 300);
     $assertion->setAuthnContext(SAML2_Constants::AC_PASSWORD);
     // build subject confirmation
     $sc = new SubjectConfirmation();
     $sc->Method = SAML2_Constants::CM_BEARER;
     $sc->SubjectConfirmationData = new SubjectConfirmationData();
     $sc->SubjectConfirmationData->NotOnOrAfter = $assertion->getNotOnOrAfter();
     $sc->SubjectConfirmationData->Recipient = $request->getAssertionConsumerServiceURL();
     $sc->SubjectConfirmationData->InResponseTo = $request->getId();
     $assertion->setSubjectConfirmation([$sc]);
     // set NameID
     $assertion->setNameId(['Format' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', 'Value' => $Person->Username . '@' . static::$issuer]);
     // set additional attributes
     $assertion->setAttributes(['User.Email' => [$Person->Email], 'User.Username' => [$Person->Username]]);
     // attach assertion to response
     $response->setAssertions([$assertion]);
     // create signature
     $privateKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type' => 'private']);
     $privateKey->loadKey(static::$privateKey);
     $response->setSignatureKey($privateKey);
     $response->setCertificates([static::$certificate]);
     // prepare response
     $responseXML = $response->toSignedXML();
     $responseString = $responseXML->ownerDocument->saveXML($responseXML);
     // dump response and quit
     #        header('Content-Type: text/xml');
     #        die($responseString);
     // send response
     $responseBinding = new HTTPPost();
     $responseBinding->send($response);
 }
Example #9
0
 public function __doRequest($request, $location, $saction, $version)
 {
     $doc = new DOMDocument('1.0');
     $doc->loadXML($request);
     $objWSSE = new WSSESoap($doc);
     /* add Timestamp with no expiration timestamp */
     $objWSSE->addTimestamp();
     /* create new XMLSec Key using RSA SHA-1 and type is private key */
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
     /* load the private key from file - last arg is bool if key in file (true) or is string (FALSE) */
     $objKey->loadKey(PRIVATE_KEY, true);
     /* Sign the message - also signs appropraite WS-Security items */
     $objWSSE->signSoapDoc($objKey);
     /* Add certificate (BinarySecurityToken) to the message and attach pointer to Signature */
     $token = $objWSSE->addBinaryToken(file_get_contents(CERT_FILE));
     $objWSSE->attachTokentoSig($token);
     return parent::__doRequest($objWSSE->saveXML(), $location, $saction, $version);
 }
Example #10
0
 /**
  * @param XMLSecurityKey $key
  * @param string         $algorithm
  *
  * @throws \LightSaml\Error\LightSamlSecurityException
  * @throws \InvalidArgumentException
  *
  * @return XMLSecurityKey
  */
 public static function castKey(XMLSecurityKey $key, $algorithm)
 {
     if (false == is_string($algorithm)) {
         throw new \InvalidArgumentException('Algorithm must be string');
     }
     // do nothing if algorithm is already the type of the key
     if ($key->type === $algorithm) {
         return $key;
     }
     $keyInfo = openssl_pkey_get_details($key->key);
     if ($keyInfo === false) {
         throw new LightSamlSecurityException('Unable to get key details from XMLSecurityKey.');
     }
     if (false == isset($keyInfo['key'])) {
         throw new LightSamlSecurityException('Missing key in public key details.');
     }
     $newKey = new XMLSecurityKey($algorithm, array('type' => 'public'));
     $newKey->loadKey($keyInfo['key']);
     return $newKey;
 }
 /**
  * @param XMLSecurityKey $inputKey
  *
  * @throws \Exception
  */
 protected function decryptSymmetricKey(XMLSecurityKey $inputKey)
 {
     /** @var XMLSecEnc $encKey */
     $encKey = $this->symmetricKeyInfo->encryptedCtx;
     $this->symmetricKeyInfo->key = $inputKey->key;
     $keySize = $this->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 LightSamlSecurityException(sprintf("Unknown key size for encryption algorithm: '%s'", $this->symmetricKey->type));
     }
     /** @var string $key */
     $key = $encKey->decryptKey($this->symmetricKeyInfo);
     if (false == is_string($key)) {
         throw new \LogicException('Expected string');
     }
     if (strlen($key) != $keySize) {
         throw new LightSamlSecurityException(sprintf("Unexpected key size of '%s' bits for encryption algorithm '%s', expected '%s' bits size", strlen($key) * 8, $this->symmetricKey->type, $keySize));
     }
     $this->symmetricKey->loadkey($key);
 }
Example #12
0
 /**
  * Encrypt the NameID in the AuthnRequest.
  *
  * @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);
     Utils::addNameId($root, $this->nameId);
     $nameId = $root->firstChild;
     Utils::getContainer()->debugMessage($nameId, 'encrypt');
     /* Encrypt the NameID. */
     $enc = new XMLSecEnc();
     $enc->setNode($nameId);
     // @codingStandardsIgnoreStart
     $enc->type = XMLSecEnc::Element;
     // @codingStandardsIgnoreEnd
     $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
     $symmetricKey->generateSessionKey();
     $enc->encryptKey($key, $symmetricKey);
     $this->encryptedNameId = $enc->encryptNode($symmetricKey);
     $this->nameId = null;
 }
Example #13
0
 /**
  * 
  * @param \Ondrejnov\EET\Receipt $receipt
  * @return array
  */
 public function getCheckCodes(Receipt $receipt)
 {
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']);
     $objKey->loadKey($this->key, TRUE);
     $arr = [$receipt->dic_popl, $receipt->id_provoz, $receipt->id_pokl, $receipt->porad_cis, $receipt->dat_trzby->format('c'), Format::price($receipt->celk_trzba)];
     $sign = $objKey->signData(join('|', $arr));
     return ['pkp' => ['_' => $sign, 'digest' => 'SHA256', 'cipher' => 'RSA2048', 'encoding' => 'base64'], 'bkp' => ['_' => Format::BKB(sha1($sign)), 'digest' => 'SHA1', 'encoding' => 'base16']];
 }
Example #14
0
 /**
  * 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(Constants::NS_SAML, 'saml:AttributeStatement');
     $root->appendChild($attributeStatement);
     foreach ($this->attributes as $name => $values) {
         $document2 = DOMDocumentFactory::create();
         $attribute = $document2->createElementNS(Constants::NS_SAML, 'saml:Attribute');
         $attribute->setAttribute('Name', $name);
         $document2->appendChild($attribute);
         if ($this->nameFormat !== Constants::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(Constants::NS_SAML, 'saml:AttributeValue');
             $attribute->appendChild($attributeValue);
             if ($type !== null) {
                 $attributeValue->setAttributeNS(Constants::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(Constants::NS_SAML, 'saml:EncryptedAttribute');
         $attributeStatement->appendChild($EncAttribute);
         $n = $document->importNode($EncrNode, true);
         $EncAttribute->appendChild($n);
     }
 }
 public function signDocument()
 {
     if (strlen($this->content2SignIdentifier) == 0) {
         return;
     }
     // get content to sign
     // get content to sign
     $doc = new DOMDocument('1.0', 'UTF-8');
     $doc->loadXML($this->xmlMessage);
     $xpath = new DOMXPath($doc);
     $nodeset = $xpath->query("//{$this->content2SignIdentifier}")->item(0);
     // sign
     // sign
     $objXMLSecDSig = new XMLSecurityDSig('');
     $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
     $objXMLSecDSig->addReference($nodeset, XMLSecurityDSig::SHA256, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'), array('id_name' => 'Id', 'uri' => $this->msgIdentifier, 'overwrite' => false));
     openssl_pkcs12_read(file_get_contents($this->myCertificatePathP12), $raw, $this->myCertificatePassword);
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'private'));
     $objKey->loadKey($raw['pkey']);
     $objXMLSecDSig->sign($objKey, $nodeset);
     $objXMLSecDSig->add509Cert($raw['cert'], true, false, array('issuerSerial' => true, 'subjectName' => true, 'issuerCertificate' => false));
     $this->xmlMessage = $doc->saveXML();
 }
Example #16
0
 /**
  * @param null|XMLSecurityKey $objBaseKey
  * @param null|DOMNode $node
  * @return null|XMLSecurityKey
  * @throws Exception
  */
 public static function staticLocateKeyInfo($objBaseKey = null, $node = null)
 {
     if (empty($node) || !$node instanceof DOMNode) {
         return null;
     }
     $doc = $node->ownerDocument;
     if (!$doc) {
         return null;
     }
     $xpath = new DOMXPath($doc);
     $xpath->registerNamespace('xmlsecenc', self::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");
                         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':
                 $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;
 }
Example #17
0
 /**
  * @return XMLSecurityKey
  */
 public static function getPublicKey2Sha1()
 {
     $publicKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
     $publicKey->loadKey(self::PUBLIC_KEY_2_PEM);
     return $publicKey;
 }
 /**
  * Retrieve certificates that sign this element.
  *
  * @return array Array with certificates.
  */
 public function getValidatingCertificates()
 {
     $ret = array();
     foreach ($this->certificates as $cert) {
         /* Construct a PEM formatted certificate */
         $pemCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($cert, 64) . "-----END CERTIFICATE-----\n";
         /* Extract the public key from the certificate for validation. */
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
         $key->loadKey($pemCert);
         try {
             /* Check the signature. */
             if ($this->validate($key)) {
                 $ret[] = $cert;
             }
         } catch (\Exception $e) {
             /* This certificate does not sign this element. */
         }
     }
     return $ret;
 }
Example #19
0
 /**
  * @throws \LightSaml\Error\LightSamlException
  *
  * @return string
  */
 public function getFingerprint()
 {
     if (false == $this->data) {
         throw new LightSamlException('Certificate data not set');
     }
     return XMLSecurityKey::getRawThumbprint($this->toPem());
 }
Example #20
0
 /**
  * Encrypt an assertion.
  *
  * This function takes in a \SAML2\Assertion and encrypts it if encryption of
  * assertions are enabled in the metadata.
  *
  * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
  * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
  * @param \SAML2\Assertion $assertion The assertion we are encrypting.
  *
  * @return \SAML2\Assertion|\SAML2\EncryptedAssertion  The assertion.
  *
  * @throws SimpleSAML_Error_Exception In case the encryption key type is not supported.
  */
 private static function encryptAssertion(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, \SAML2\Assertion $assertion)
 {
     $encryptAssertion = $spMetadata->getBoolean('assertion.encryption', null);
     if ($encryptAssertion === null) {
         $encryptAssertion = $idpMetadata->getBoolean('assertion.encryption', false);
     }
     if (!$encryptAssertion) {
         // we are _not_ encrypting this assertion, and are therefore done
         return $assertion;
     }
     $sharedKey = $spMetadata->getString('sharedkey', null);
     if ($sharedKey !== null) {
         $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
         $key->loadKey($sharedKey);
     } else {
         $keys = $spMetadata->getPublicKeys('encryption', true);
         $key = $keys[0];
         switch ($key['type']) {
             case 'X509Certificate':
                 $pemKey = "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
                 break;
             default:
                 throw new SimpleSAML_Error_Exception('Unsupported encryption key type: ' . $key['type']);
         }
         // extract the public key from the certificate for encryption
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
         $key->loadKey($pemKey);
     }
     $ea = new \SAML2\EncryptedAssertion();
     $ea->setAssertion($assertion, $key);
     return $ea;
 }
Example #21
0
 public function verify(DOMDocument $data)
 {
     $objKey = null;
     $objXMLSecDSig = new XMLSecurityDSig();
     $objDSig = $objXMLSecDSig->locateSignature($data);
     if (!$objDSig) {
         throw new UnexpectedValueException('Signature DOM element not found.');
     }
     $objXMLSecDSig->canonicalizeSignedInfo();
     if (!$this->getPublicKey()) {
         // try to get the public key from the certificate
         $objKey = $objXMLSecDSig->locateKey();
         if (!$objKey) {
             throw new RuntimeException('There is no set either private key or public key for signature verification.');
         }
         XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
         $this->publicKey = $objKey->getX509Certificate();
         $this->keyAlgorithm = $objKey->getAlgorith();
     }
     if (!$objKey) {
         $objKey = new XMLSecurityKey($this->keyAlgorithm, ['type' => 'public']);
         $objKey->loadKey($this->getPublicKey());
     }
     // Check signature
     if (1 !== $objXMLSecDSig->verify($objKey)) {
         return false;
     }
     // Check references (data)
     try {
         $objXMLSecDSig->validateReference();
     } catch (\Exception $e) {
         return false;
     }
     return true;
 }
Example #22
0
 /**
  * @param XMLSecurityKey $objKey
  * @param null|DOMNode $parent
  */
 public function appendKey($objKey, $parent = null)
 {
     $objKey->serializeKey($parent);
 }
Example #23
0
 /**
  * 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. */
             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>';
     try {
         $newDoc = DOMDocumentFactory::fromString($xml);
     } catch (RuntimeException $e) {
         throw new \Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?', 0, $e);
     }
     $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;
 }
Example #24
0
 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;
 }
 /**
  * @param string $returnTo Where to have IdP send user after login
  * @param \yii\web\Request|null $request
  * @return \Sil\IdpPw\Common\Auth\User
  * @throws \Sil\IdpPw\Common\Auth\InvalidLoginException
  * @throws RedirectException
  */
 public function login($returnTo, Request $request = null)
 {
     $container = new SamlContainer();
     ContainerSingleton::setContainer($container);
     $request = new AuthnRequest();
     $request->setId($container->generateId());
     $request->setIssuer($this->entityId);
     $request->setDestination($this->ssoUrl);
     $request->setRelayState($returnTo);
     /*
      * Sign request if spCertificate and spPrivateKey are provided
      */
     if ($this->signRequest) {
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type' => 'private']);
         $key->loadKey($this->spPrivateKey, false);
         $request->setSignatureKey($key);
     }
     try {
         /*
          * Check for SAMLRequest or SAMLResponse to see if user is returning after login
          */
         $binding = new HTTPPost();
         /** @var \SAML2\Response $response */
         $response = $binding->receive();
     } catch (\Exception $e) {
         /*
          * User was not logged in, so redirect to IdP for login
          */
         $binding = new HTTPRedirect();
         $url = $binding->getRedirectURL($request);
         throw new RedirectException($url);
     }
     try {
         /*
          * If needed, check if response is signed
          */
         if ($this->checkResponseSigning) {
             $idpKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type' => 'public']);
             $idpKey->loadKey($this->idpCertificate, false, true);
             if (!$response->validate($idpKey)) {
                 throw new \Exception('SAML response was not signed properly', 1459884735);
             }
         }
         /** @var \SAML2\Assertion[]|\SAML2\EncryptedAssertion[] $assertions */
         $assertions = $response->getAssertions();
         /*
          * If requiring encrypted assertion, use key to decrypt it
          */
         if ($this->requireEncryptedAssertion) {
             $decryptKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, ['type' => 'private']);
             $decryptKey->loadKey($this->spPrivateKey, false, false);
             if (!$assertions[0] instanceof EncryptedAssertion) {
                 throw new \Exception('Response assertion is required to be encrypted but was not', 1459884392);
             }
             $assertion = $assertions[0]->getAssertion($decryptKey);
         } else {
             $assertion = $assertions[0];
         }
         /*
          * Get attributes using mapping config, make sure expected fields
          * are present, and return as new User
          */
         /** @var \SAML2\Assertion $assertion */
         $samlAttrs = $assertion->getAttributes();
         $normalizedAttrs = $this->extractSamlAttributes($samlAttrs, $this->attributeMap);
         $this->assertHasRequiredSamlAttributes($normalizedAttrs, $this->attributeMap);
         $authUser = new AuthUser();
         $authUser->firstName = $normalizedAttrs['first_name'];
         $authUser->lastName = $normalizedAttrs['last_name'];
         $authUser->email = $normalizedAttrs['email'];
         $authUser->employeeId = $normalizedAttrs['employee_id'];
         $authUser->idpUsername = $normalizedAttrs['idp_username'];
         return $authUser;
     } catch (\Exception $e) {
         /*
          * An error occurred processing SAML data
          */
         throw new InvalidLoginException($e->getMessage(), 1459803743);
     }
 }
Example #26
0
 /**
  * @return XMLSecurityKey
  */
 public static function getPrivateKey()
 {
     $privateKey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
     $privateKey->loadKey(self::PRIVATE_KEY_PEM);
     return $privateKey;
 }