diff --git a/lib/SimpleSAML/XML/Validator.php b/lib/SimpleSAML/XML/Validator.php
index d3fba00114dce38b0456db80bda5abe3828904cd..ddd404b28e905b45f847f1efe3ccf4a4a9368b24 100644
--- a/lib/SimpleSAML/XML/Validator.php
+++ b/lib/SimpleSAML/XML/Validator.php
@@ -24,14 +24,33 @@ class SimpleSAML_XML_Validator {
 	/**
 	 * This function initializes the validator.
 	 *
-	 * @param $xmlNode  The XML node which contains the Signature element.
-	 * @param $idAttribute  The ID attribute which is used in node references. If this attribute is
-	 *                      NULL (the default), then we will use whatever is the default ID. Can be eigther
-	 *						a string with one value, or an array with multiple ID attrbute names.
+	 * This function accepts an optional parameter $publickey, which is the public key
+	 * or certificate which should be used to validate the signature. This parameter can
+	 * take the following values:
+	 * - NULL/FALSE: No validation will be performed. This is the default.
+	 * - A string: Assumed to be a PEM-encoded certificate / public key.
+	 * - An array: Assumed to be an array returned by SimpleSAML_Utilities::loadPublicKey.
+	 *
+	 * @param DOMNode $xmlNode  The XML node which contains the Signature element.
+	 * @param string|array $idAttribute  The ID attribute which is used in node references. If
+	 *          this attribute is NULL (the default), then we will use whatever is the default
+	 *          ID. Can be eigther a string with one value, or an array with multiple ID
+	 *          attrbute names.
+	 * @param array $publickey  The public key / certificate which should be used to validate the XML node.
 	 */
 	public function __construct($xmlNode, $idAttribute = NULL, $publickey = FALSE) {
 		assert('$xmlNode instanceof DOMNode');
 
+		if ($publickey === NULL) {
+			$publickey = FALSE;
+		} elseif(is_string($publickey)) {
+			$publickey = array(
+				'PEM' => $publickey,
+			);
+		} else {
+			assert('$publickey === FALSE || is_array($publickey)');
+		}
+
 		/* Create an XML security object. */
 		$objXMLSecDSig = new XMLSecurityDSig();
 
@@ -67,13 +86,35 @@ class SimpleSAML_XML_Validator {
 		}
 
 		/* Load the key data. */
-		if ($publickey) {
-			$objKey->loadKey($publickey);
+		if (array_key_exists('PEM', $publickey)) {
+			/* We have PEM data for the public key / certificate. */
+			$objKey->loadKey($publickey['PEM']);
 		} else {
+			/* No PEM data. Search for key in signature. */
+
 			if (!XMLSecEnc::staticLocateKeyInfo($objKey, $signatureElement)) {
 				throw new Exception('Error finding key data for XML signature validation.');
 			}
+
+			if ($publickey !== FALSE) {
+				/* $publickey is set, and should therefore contain one or more fingerprints.
+				 * Check that the response contains a certificate with a matching
+				 * fingerprint.
+				 */
+				assert('is_array($publickey["certFingerprint"])');
+
+				$certificate = $objKey->getX509Certificate();
+				if ($certificate === NULL) {
+					/* Wasn't signed with an X509 certificate. */
+					throw new Exception('Message wasn\'t signed with an X509 certificate,' .
+						' and no public key was provided in the metadata.');
+				}
+
+				self::validateCertificateFingerprint($certificate, $publickey['certFingerprint']);
+				/* Key OK. */
+			}
 		}
+
 		/* Check the signature. */
 		if (! $objXMLSecDSig->verify($objKey)) {
 			throw new Exception("Unable to validate Signature");
@@ -140,6 +181,42 @@ class SimpleSAML_XML_Validator {
 	}
 
 
+	/**
+	 * Helper function for validating the fingerprint.
+	 *
+	 * Checks the fingerprint of a certificate against an array of valid fingerprints.
+	 * Will throw an exception if none of the fingerprints matches.
+	 *
+	 * @param string $certificate  The X509 certificate we should validate.
+	 * @param array $fingerprints  The valid fingerprints.
+	 */
+	private static function validateCertificateFingerprint($certificate, $fingerprints) {
+		assert('is_string($certificate)');
+		assert('is_array($fingerprints)');
+
+		$certFingerprint = self::calculateX509Fingerprint($certificate);
+		if ($certFingerprint === NULL) {
+			/* Couldn't calculate fingerprint from X509 certificate. Should not happen. */
+			throw new Exception('Unable to calculate fingerprint from X509' .
+				' certificate. Maybe it isn\'t an X509 certificate?');
+		}
+
+		foreach ($fingerprints as $fp) {
+			assert('is_string($fp)');
+
+			if ($fp === $certFingerprint) {
+				/* The fingerprints matched. */
+				return;
+			}
+
+		}
+
+		/* None of the fingerprints matched. Throw an exception describing the error. */
+		throw new Exception('Invalid fingerprint of certificate. Expected one of [' .
+			implode('], [', $fingerprints) . '], but got [' . $certFingerprint . ']');
+	}
+
+
 	/**
 	 * Validate the fingerprint of the certificate which was used to sign this document.
 	 *
@@ -156,28 +233,20 @@ class SimpleSAML_XML_Validator {
 		if($this->x509Certificate === NULL) {
 			throw new Exception('Key used to sign the message was not an X509 certificate.');
 		}
-		$certFingerprint = self::calculateX509Fingerprint($this->x509Certificate);
 
 		if(!is_array($fingerprints)) {
 			$fingerprints = array($fingerprints);
 		}
 
-		foreach($fingerprints as $fp) {
+		/* Normalize the fingerprints. */
+		foreach($fingerprints as &$fp) {
 			assert('is_string($fp)');
 
 			/* Make sure that the fingerprint is in the correct format. */
 			$fp = strtolower(str_replace(":", "", $fp));
-
-			if($fp === $certFingerprint) {
-				/* The fingerprints matched. */
-				return;
-			}
-
 		}
 
-		/* None of the fingerprints matched. Throw an exception describing the error. */
-		throw new Exception('Invalid fingerprint of certificate. Expected one of [' .
-			implode('], [', $fingerprints) . '], but got [' . $certFingerprint . ']');
+		self::validateCertificateFingerprint($this->x509Certificate, $fingerprints);
 	}