getPublicKeys() public method

Get public key from metadata.
public getPublicKeys ( string | null $use = null, boolean $required = false, string $prefix = '' ) : array | null
$use string | null The purpose this key can be used for. (encryption or signing).
$required boolean Whether the public key is required. If this is true, a missing key will cause an exception. Default is false.
$prefix string The prefix which should be used when reading from the metadata array. Defaults to ''.
return array | null Public key data, or null if no public key or was found.
 /**
  * Add a certificate.
  *
  * Helper function for adding a certificate to the metadata.
  *
  * @param \SAML2\XML\md\RoleDescriptor $rd The RoleDescriptor the certificate should be added to.
  * @param SimpleSAML_Configuration    $metadata The metadata of the entity.
  */
 private function addCertificate(\SAML2\XML\md\RoleDescriptor $rd, SimpleSAML_Configuration $metadata)
 {
     $keys = $metadata->getPublicKeys();
     if ($keys !== null) {
         foreach ($keys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             if (!isset($key['signing']) || $key['signing'] === true) {
                 $this->addX509KeyDescriptor($rd, 'signing', $key['X509Certificate']);
             }
             if (!isset($key['encryption']) || $key['encryption'] === true) {
                 $this->addX509KeyDescriptor($rd, 'encryption', $key['X509Certificate']);
             }
         }
     }
     if ($metadata->hasValue('https.certData')) {
         $this->addX509KeyDescriptor($rd, 'signing', $metadata->getString('https.certData'));
     }
 }
Esempio n. 2
0
 /**
  * Get public key or certificate from metadata.
  *
  * This function implements a function to retrieve the public key or certificate from
  * a metadata array.
  *
  * It will search for the following elements in the metadata:
  * 'certData'  The certificate as a base64-encoded string.
  * 'certificate'  A file with a certificate or public key in PEM-format.
  * 'certFingerprint'  The fingerprint of the certificate. Can be a single fingerprint,
  *                    or an array of multiple valid fingerprints.
  *
  * This function will return an array with these elements:
  * 'PEM'  The public key/certificate in PEM-encoding.
  * 'certData'  The certificate data, base64 encoded, on a single line. (Only
  *             present if this is a certificate.)
  * 'certFingerprint'  Array of valid certificate fingerprints. (Only present
  *                    if this is a certificate.)
  *
  * @param SimpleSAML_Configuration $metadata  The metadata.
  * @param bool $required  Whether the private key is required. If this is TRUE, a
  *                        missing key will cause an exception. Default is FALSE.
  * @param string $prefix  The prefix which should be used when reading from the metadata
  *                        array. Defaults to ''.
  * @return array|NULL  Public key or certificate data, or NULL if no public key or
  *                     certificate was found.
  */
 public static function loadPublicKey(SimpleSAML_Configuration $metadata, $required = FALSE, $prefix = '')
 {
     assert('is_bool($required)');
     assert('is_string($prefix)');
     $keys = $metadata->getPublicKeys(NULL, FALSE, $prefix);
     if ($keys !== NULL) {
         foreach ($keys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             if ($key['signing'] !== TRUE) {
                 continue;
             }
             $certData = $key['X509Certificate'];
             $pem = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certData, 64) . "-----END CERTIFICATE-----\n";
             $certFingerprint = strtolower(sha1(base64_decode($certData)));
             return array('certData' => $certData, 'PEM' => $pem, 'certFingerprint' => array($certFingerprint));
         }
         /* No valid key found. */
     } elseif ($metadata->hasValue($prefix . 'certFingerprint')) {
         /* We only have a fingerprint available. */
         $fps = $metadata->getArrayizeString($prefix . 'certFingerprint');
         /* Normalize fingerprint(s) - lowercase and no colons. */
         foreach ($fps as &$fp) {
             assert('is_string($fp)');
             $fp = strtolower(str_replace(':', '', $fp));
         }
         /* We can't build a full certificate from a fingerprint, and may as well
          * return an array with only the fingerprint(s) immediately.
          */
         return array('certFingerprint' => $fps);
     }
     /* No public key/certificate available. */
     if ($required) {
         throw new Exception('No public key / certificate found in metadata.');
     } else {
         return NULL;
     }
 }
Esempio n. 3
0
 /**
  * This function receives a SAML 1.1 artifact.
  *
  * @param SimpleSAML_Configuration $spMetadata  The metadata of the SP.
  * @param SimpleSAML_Configuration $idpMetadata  The metadata of the IdP.
  * @return string  The <saml1p:Response> element, as an XML string.
  */
 public static function receive(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata)
 {
     $artifacts = self::getArtifacts();
     $request = self::buildRequest($artifacts);
     \SimpleSAML\Utils\XML::debugSAMLMessage($request, 'out');
     $url = $idpMetadata->getDefaultEndpoint('ArtifactResolutionService', array('urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding'));
     $url = $url['Location'];
     $peerPublicKeys = $idpMetadata->getPublicKeys('signing', TRUE);
     $certData = '';
     foreach ($peerPublicKeys as $key) {
         if ($key['type'] !== 'X509Certificate') {
             continue;
         }
         $certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
     }
     $file = SimpleSAML\Utils\System::getTempDir() . DIRECTORY_SEPARATOR . sha1($certData) . '.crt';
     if (!file_exists($file)) {
         SimpleSAML\Utils\System::writeFile($file, $certData);
     }
     $spKeyCertFile = \SimpleSAML\Utils\Config::getCertPath($spMetadata->getString('privatekey'));
     $opts = array('ssl' => array('verify_peer' => TRUE, 'cafile' => $file, 'local_cert' => $spKeyCertFile, 'capture_peer_cert' => TRUE, 'capture_peer_chain' => TRUE), 'http' => array('method' => 'POST', 'content' => $request, 'header' => 'SOAPAction: http://www.oasis-open.org/committees/security' . "\r\n" . 'Content-Type: text/xml'));
     // Fetch the artifact
     $response = \SimpleSAML\Utils\HTTP::fetch($url, $opts);
     if ($response === FALSE) {
         throw new SimpleSAML_Error_Exception('Failed to retrieve assertion from IdP.');
     }
     \SimpleSAML\Utils\XML::debugSAMLMessage($response, 'in');
     // Find the response in the SOAP message
     $response = self::extractResponse($response);
     return $response;
 }
Esempio n. 4
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.
  */
 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;
 }
Esempio n. 5
0
 /**
  * Retrieve the encryption key for the given entity.
  *
  * @param SimpleSAML_Configuration $metadata  The metadata of the entity.
  * @return XMLSecurityKey  The encryption key.
  */
 public static function getEncryptionKey(SimpleSAML_Configuration $metadata)
 {
     $sharedKey = $metadata->getString('sharedkey', NULL);
     if ($sharedKey !== NULL) {
         $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
         $key->loadKey($sharedKey);
         return $key;
     }
     $keys = $metadata->getPublicKeys('encryption', TRUE);
     foreach ($keys as $key) {
         switch ($key['type']) {
             case 'X509Certificate':
                 $pemKey = "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
                 $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
                 $key->loadKey($pemKey);
                 return $key;
         }
     }
     throw new SimpleSAML_Error_Exception('No supported encryption key in ' . var_export($metadata->getString('entityid'), TRUE));
 }
Esempio n. 6
0
 /**
  * This function sends the SOAP message to the service location and returns SOAP response
  *
  * @param SAML2_Message $m  The request that should be sent.
  * @param SimpleSAML_Configuration $srcMetadata  The metadata of the issuer of the message.
  * @param SimpleSAML_Configuration $dstMetadata  The metadata of the destination of the message.
  * @return SAML2_Message  The response we received.
  */
 public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL)
 {
     $issuer = $msg->getIssuer();
     $ctxOpts = array('ssl' => array('capture_peer_cert' => TRUE));
     // Determine if we are going to do a MutualSSL connection between the IdP and SP  - Shoaib
     if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) {
         $ctxOpts['ssl']['local_cert'] = SimpleSAML_Utilities::resolveCert($srcMetadata->getString('saml.SOAPClient.certificate'));
         if ($srcMetadata->hasValue('saml.SOAPClient.privatekey_pass')) {
             $ctxOpts['ssl']['passphrase'] = $srcMetadata->getString('saml.SOAPClient.privatekey_pass');
         }
     } else {
         /* Use the SP certificate and privatekey if it is configured. */
         $privateKey = SimpleSAML_Utilities::loadPrivateKey($srcMetadata);
         $publicKey = SimpleSAML_Utilities::loadPublicKey($srcMetadata);
         if ($privateKey !== NULL && $publicKey !== NULL && isset($publicKey['PEM'])) {
             $keyCertData = $privateKey['PEM'] . $publicKey['PEM'];
             $file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($keyCertData) . '.pem';
             if (!file_exists($file)) {
                 SimpleSAML_Utilities::writeFile($file, $keyCertData);
             }
             $ctxOpts['ssl']['local_cert'] = $file;
             if (isset($privateKey['password'])) {
                 $ctxOpts['ssl']['passphrase'] = $privateKey['password'];
             }
         }
     }
     // do peer certificate verification
     if ($dstMetadata !== NULL) {
         $peerPublicKeys = $dstMetadata->getPublicKeys('signing', TRUE);
         $certData = '';
         foreach ($peerPublicKeys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             $certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
         }
         $peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
         if (!file_exists($peerCertFile)) {
             SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
         }
         // create ssl context
         $ctxOpts['ssl']['verify_peer'] = TRUE;
         $ctxOpts['ssl']['verify_depth'] = 1;
         $ctxOpts['ssl']['cafile'] = $peerCertFile;
     }
     $context = stream_context_create($ctxOpts);
     if ($context === NULL) {
         throw new Exception('Unable to create SSL stream context');
     }
     $options = array('uri' => $issuer, 'location' => $msg->getDestination(), 'stream_context' => $context);
     $x = new SoapClient(NULL, $options);
     // Add soap-envelopes
     $request = $msg->toSignedXML();
     $request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE;
     SimpleSAML_Utilities::debugMessage($request, 'out');
     $action = 'http://www.oasis-open.org/committees/security';
     $version = '1.1';
     $destination = $msg->getDestination();
     /* Perform SOAP Request over HTTP */
     $soapresponsexml = $x->__doRequest($request, $destination, $action, $version);
     if ($soapresponsexml === NULL || $soapresponsexml === "") {
         throw new Exception('Empty SOAP response, check peer certificate.');
     }
     SimpleSAML_Utilities::debugMessage($soapresponsexml, 'in');
     // Convert to SAML2_Message (DOMElement)
     $dom = new DOMDocument();
     if (!$dom->loadXML($soapresponsexml)) {
         throw new Exception('Not a SOAP response.');
     }
     $soapfault = $this->getSOAPFault($dom);
     if (isset($soapfault)) {
         throw new Exception($soapfault);
     }
     //Extract the message from the response
     $xml = $dom->firstChild;
     /* Soap Envelope */
     $samlresponse = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]');
     $samlresponse = SAML2_Message::fromXML($samlresponse[0]);
     /* Add validator to message which uses the SSL context. */
     self::addSSLValidator($samlresponse, $context);
     SimpleSAML_Logger::debug("Valid ArtifactResponse received from IdP");
     return $samlresponse;
 }
Esempio n. 7
0
 /**
  * Get public key or certificate from metadata.
  *
  * This function implements a function to retrieve the public key or certificate from a metadata array.
  *
  * It will search for the following elements in the metadata:
  * - 'certData': The certificate as a base64-encoded string.
  * - 'certificate': A file with a certificate or public key in PEM-format.
  * - 'certFingerprint': The fingerprint of the certificate. Can be a single fingerprint, or an array of multiple
  * valid fingerprints.
  *
  * This function will return an array with these elements:
  * - 'PEM': The public key/certificate in PEM-encoding.
  * - 'certData': The certificate data, base64 encoded, on a single line. (Only present if this is a certificate.)
  * - 'certFingerprint': Array of valid certificate fingerprints. (Only present if this is a certificate.)
  *
  * @param \SimpleSAML_Configuration $metadata The metadata.
  * @param bool                      $required Whether the private key is required. If this is TRUE, a missing key
  *     will cause an exception. Default is FALSE.
  * @param string                    $prefix The prefix which should be used when reading from the metadata array.
  *     Defaults to ''.
  *
  * @return array|NULL Public key or certificate data, or NULL if no public key or certificate was found.
  * @throws \InvalidArgumentException If $metadata is not an instance of \SimpleSAML_Configuration, $required is not
  *     boolean or $prefix is not a string.
  * @throws \SimpleSAML_Error_Exception If no private key is found in the metadata, or it was not possible to load
  *     it.
  *
  * @author Andreas Solberg, UNINETT AS <*****@*****.**>
  * @author Olav Morken, UNINETT AS <*****@*****.**>
  * @author Lasse Birnbaum Jensen
  */
 public static function loadPublicKey(\SimpleSAML_Configuration $metadata, $required = false, $prefix = '')
 {
     if (!is_bool($required) || !is_string($prefix)) {
         throw new \InvalidArgumentException('Invalid input parameters.');
     }
     $keys = $metadata->getPublicKeys(null, false, $prefix);
     if ($keys !== null) {
         foreach ($keys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             if ($key['signing'] !== true) {
                 continue;
             }
             $certData = $key['X509Certificate'];
             $pem = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certData, 64) . "-----END CERTIFICATE-----\n";
             $certFingerprint = strtolower(sha1(base64_decode($certData)));
             return array('certData' => $certData, 'PEM' => $pem, 'certFingerprint' => array($certFingerprint));
         }
         // no valid key found
     } elseif ($metadata->hasValue($prefix . 'certFingerprint')) {
         // we only have a fingerprint available
         $fps = $metadata->getArrayizeString($prefix . 'certFingerprint');
         // normalize fingerprint(s) - lowercase and no colons
         foreach ($fps as &$fp) {
             assert('is_string($fp)');
             $fp = strtolower(str_replace(':', '', $fp));
         }
         // We can't build a full certificate from a fingerprint, and may as well return an array with only the
         //fingerprint(s) immediately.
         return array('certFingerprint' => $fps);
     }
     // no public key/certificate available
     if ($required) {
         throw new \SimpleSAML_Error_Exception('No public key / certificate found in metadata.');
     } else {
         return null;
     }
 }
Esempio n. 8
0
 /**
  * This function sends the SOAP message to the service location and returns SOAP response
  *
  * @param  SAML2_Message            $msg         The request that should be sent.
  * @param  SimpleSAML_Configuration $srcMetadata The metadata of the issuer of the message.
  * @param  SimpleSAML_Configuration $dstMetadata The metadata of the destination of the message.
  * @return SAML2_Message            The response we received.
  * @throws Exception
  */
 public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL)
 {
     $issuer = $msg->getIssuer();
     $ctxOpts = array('ssl' => array('capture_peer_cert' => TRUE));
     /* Determine if we are going to do a MutualSSL connection between the IdP and SP  - Shoaib */
     if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) {
         $cert = $srcMetadata->getValue('saml.SOAPClient.certificate');
         if ($cert !== FALSE) {
             $ctxOpts['ssl']['local_cert'] = SimpleSAML_Utilities::resolveCert($srcMetadata->getString('saml.SOAPClient.certificate'));
             if ($srcMetadata->hasValue('saml.SOAPClient.privatekey_pass')) {
                 $ctxOpts['ssl']['passphrase'] = $srcMetadata->getString('saml.SOAPClient.privatekey_pass');
             }
         }
     } else {
         /* Use the SP certificate and privatekey if it is configured. */
         $privateKey = SimpleSAML_Utilities::loadPrivateKey($srcMetadata);
         $publicKey = SimpleSAML_Utilities::loadPublicKey($srcMetadata);
         if ($privateKey !== NULL && $publicKey !== NULL && isset($publicKey['PEM'])) {
             $keyCertData = $privateKey['PEM'] . $publicKey['PEM'];
             $file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($keyCertData) . '.pem';
             if (!file_exists($file)) {
                 SimpleSAML_Utilities::writeFile($file, $keyCertData);
             }
             $ctxOpts['ssl']['local_cert'] = $file;
             if (isset($privateKey['password'])) {
                 $ctxOpts['ssl']['passphrase'] = $privateKey['password'];
             }
         }
     }
     /* Do peer certificate verification */
     if ($dstMetadata !== NULL) {
         $peerPublicKeys = $dstMetadata->getPublicKeys('signing', TRUE);
         $certData = '';
         foreach ($peerPublicKeys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             $certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
         }
         $peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
         if (!file_exists($peerCertFile)) {
             SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
         }
         /* Create ssl context */
         $ctxOpts['ssl']['verify_peer'] = TRUE;
         $ctxOpts['ssl']['verify_depth'] = 1;
         $ctxOpts['ssl']['cafile'] = $peerCertFile;
     }
     $ctxOpts['http']['header'] = 'SOAPAction: "http://www.oasis-open.org/committees/security"' . "\n";
     if ($this->username !== NULL && $this->password !== NULL) {
         /* Add HTTP Basic authentication header. */
         $authData = $this->username . ':' . $this->password;
         $authData = base64_encode($authData);
         $ctxOpts['http']['header'] .= 'Authorization: Basic ' . $authData . "\n";
     }
     if ($srcMetadata->hasValue('saml.SOAPClient.proxyhost')) {
         $options['proxy_host'] = $srcMetadata->getValue('saml.SOAPClient.proxyhost');
     }
     if ($srcMetadata->hasValue('saml.SOAPClient.proxyport')) {
         $options['proxy_port'] = $srcMetadata->getValue('saml.SOAPClient.proxyport');
     }
     $x = new SoapClient(NULL, $options);
     /* Add soap-envelopes */
     $request = $msg->toSignedXML();
     $request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE;
     SAML2_Utils::getContainer()->debugMessage($request, 'out');
     $ctxOpts['http']['content'] = $request;
     $ctxOpts['http']['header'] .= 'Content-Type: text/xml; charset=utf-8' . "\n";
     $ctxOpts['http']['method'] = 'POST';
     $destination = $msg->getDestination();
     /* Perform SOAP Request over HTTP */
     $context = stream_context_create($ctxOpts);
     if ($context === NULL) {
         throw new Exception('Unable to create stream context');
     }
     $soapresponsexml = @file_get_contents($destination, FALSE, $context);
     if ($soapresponsexml === FALSE) {
         throw new Exception('Error processing SOAP call: ' . SimpleSAML_Utilities::getLastError());
     }
     SAML2_Utils::getContainer()->debugMessage($soapresponsexml, 'in');
     /* Convert to SAML2_Message (DOMElement) */
     try {
         $dom = SAML2_DOMDocumentFactory::fromString($soapresponsexml);
     } catch (SAML2_Exception_RuntimeException $e) {
         throw new Exception('Not a SOAP response.', 0, $e);
     }
     $soapfault = $this->getSOAPFault($dom);
     if (isset($soapfault)) {
         throw new Exception($soapfault);
     }
     /* Extract the message from the response */
     $samlresponse = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]');
     $samlresponse = SAML2_Message::fromXML($samlresponse[0]);
     /* Add validator to message which uses the SSL context. */
     self::addSSLValidator($samlresponse, $context);
     SAML2_Utils::getContainer()->getLogger()->debug("Valid ArtifactResponse received from IdP");
     return $samlresponse;
 }
Esempio n. 9
0
 /**
  * Check the signature on a SAML2 message or assertion.
  *
  * @param SimpleSAML_Configuration $srcMetadata  The metadata of the sender.
  * @param SAML2_SignedElement $element  Either a SAML2_Response or a SAML2_Assertion.
  */
 public static function checkSign(SimpleSAML_Configuration $srcMetadata, SAML2_SignedElement $element)
 {
     /* Find the public key that should verify signatures by this entity. */
     $keys = $srcMetadata->getPublicKeys('signing');
     if ($keys !== NULL) {
         $pemKeys = array();
         foreach ($keys as $key) {
             switch ($key['type']) {
                 case 'X509Certificate':
                     $pemKeys[] = "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
                     break;
                 default:
                     SimpleSAML_Logger::debug('Skipping unknown key type: ' . $key['type']);
             }
         }
     } elseif ($srcMetadata->hasValue('certFingerprint')) {
         $certFingerprint = $srcMetadata->getArrayizeString('certFingerprint');
         foreach ($certFingerprint as &$fp) {
             $fp = strtolower(str_replace(':', '', $fp));
         }
         $certificates = $element->getCertificates();
         /*
          * We don't have the full certificate stored. Try to find it
          * in the message or the assertion instead.
          */
         if (count($certificates) === 0) {
             /* We need the full certificate in order to match it against the fingerprint. */
             SimpleSAML_Logger::debug('No certificate in message when validating against fingerprint.');
             return FALSE;
         } else {
             SimpleSAML_Logger::debug('Found ' . count($certificates) . ' certificates in ' . get_class($element));
         }
         $pemCert = self::findCertificate($certFingerprint, $certificates);
         $pemKeys = array($pemCert);
     } else {
         /* Attempt CA validation. */
         $caFile = $srcMetadata->getString('caFile', NULL);
         if ($caFile === NULL) {
             throw new SimpleSAML_Error_Exception('Missing certificate in metadata for ' . var_export($srcMetadata->getString('entityid'), TRUE));
         }
         $caFile = SimpleSAML_Utilities::resolveCert($caFile);
         if (count($certificates) === 0) {
             /* We need the full certificate in order to check it against the CA file. */
             SimpleSAML_Logger::debug('No certificate in message when validating with CA.');
             return FALSE;
         }
         /* We assume that it is the first certificate that was used to sign the message. */
         $pemCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certificates[0], 64) . "-----END CERTIFICATE-----\n";
         SimpleSAML_Utilities::validateCA($pemCert, $caFile);
         $pemKeys = array($pemCert);
     }
     SimpleSAML_Logger::debug('Has ' . count($pemKeys) . ' candidate keys for validation.');
     $lastException = NULL;
     foreach ($pemKeys as $i => $pem) {
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
         $key->loadKey($pem);
         try {
             /*
              * Make sure that we have a valid signature on either the response
              * or the assertion.
              */
             $res = $element->validate($key);
             if ($res) {
                 SimpleSAML_Logger::debug('Validation with key #' . $i . ' succeeded.');
                 return TRUE;
             }
             SimpleSAML_Logger::debug('Validation with key #' . $i . ' failed without exception.');
         } catch (Exception $e) {
             SimpleSAML_Logger::debug('Validation with key #' . $i . ' failed with exception: ' . $e->getMessage());
             $lastException = $e;
         }
     }
     /* We were unable to validate the signature with any of our keys. */
     if ($lastException !== NULL) {
         throw $lastException;
     } else {
         return FALSE;
     }
 }