From d7356580a6545563eaf7cc00e3e00714579d82de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaime=20P=C3=A9rez=20Crespo?= <jaime.perez@uninett.no>
Date: Mon, 1 Oct 2012 14:17:09 +0000
Subject: [PATCH] Support for RSA_SHA256, RSA_SHA384 and RSA_SHA512 in HTTP
 Redirect binding. Signature algorithm can now be set also in the remote IdP
 metadata, with more priority than the one specified in hosted SP metadata.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@3181 44740490-163a-0410-bde0-09ae8108e29a
---
 lib/SAML2/HTTPRedirect.php   | 22 ++++++++++------------
 lib/SAML2/Utils.php          | 25 +++++++++++--------------
 modules/saml/lib/Message.php |  6 +++++-
 3 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/lib/SAML2/HTTPRedirect.php b/lib/SAML2/HTTPRedirect.php
index 6b001de18..6033389a0 100644
--- a/lib/SAML2/HTTPRedirect.php
+++ b/lib/SAML2/HTTPRedirect.php
@@ -51,7 +51,7 @@ class SAML2_HTTPRedirect extends SAML2_Binding {
 
 		if ($key !== NULL) {
 			/* Add the signature. */
-			$msg .= '&SigAlg=' . urlencode(XMLSecurityKey::RSA_SHA1);
+			$msg .= '&SigAlg=' . urlencode($key->type);
 
 			$signature = $key->signData($msg);
 			$msg .= '&Signature=' . urlencode(base64_encode($signature));
@@ -216,17 +216,15 @@ class SAML2_HTTPRedirect extends SAML2_Binding {
 
 		$signature = base64_decode($signature);
 
-		switch ($sigAlg) {
-		case XMLSecurityKey::RSA_SHA1:
-			if ($key->type !== XMLSecurityKey::RSA_SHA1) {
-				throw new Exception('Invalid key type for validating signature on query string.');
-			}
-			if (!$key->verifySignature($query,$signature)) {
-				throw new Exception('Unable to validate signature on query string.');
-			}
-			break;
-		default:
-			throw new Exception('Unknown signature algorithm: ' . var_export($sigAlg, TRUE));
+		if ($key->type !== XMLSecurityKey::RSA_SHA1) {
+			throw new Exception('Invalid key type for validating signature on query string.');
+		}
+		if ($key->type !== $sigAlg) {
+			$key = SAML2_Utils::castKey($key, $sigAlg);
+		}
+
+		if (!$key->verifySignature($query,$signature)) {
+			throw new Exception('Unable to validate signature on query string.');
 		}
 	}
 
diff --git a/lib/SAML2/Utils.php b/lib/SAML2/Utils.php
index 79576a2b6..5120639cc 100644
--- a/lib/SAML2/Utils.php
+++ b/lib/SAML2/Utils.php
@@ -91,10 +91,17 @@ class SAML2_Utils {
 	 *
 	 * @param XMLSecurityKey $key  The key.
 	 * @param string $algorithm  The desired algorithm.
+	 * @param string $types  Public or private key, defaults to public.
 	 * @return XMLSecurityKey  The new key.
 	 */
-	private static function castKey(XMLSecurityKey $key, $algorithm) {
+	public static function castKey(XMLSecurityKey $key, $algorithm, $type = 'public') {
 		assert('is_string($algorithm)');
+		assert('$type === "public" || $type === "private"');
+
+		// 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) {
@@ -104,7 +111,7 @@ class SAML2_Utils {
 			throw new Exception('Missing key in public key details.');
 		}
 
-		$newKey = new XMLSecurityKey($algorithm, array('type'=>'public'));
+		$newKey = new XMLSecurityKey($algorithm, array('type'=>$type));
 		$newKey->loadKey($keyInfo['key']);
 		return $newKey;
 	}
@@ -133,18 +140,8 @@ class SAML2_Utils {
 		}
 		$algo = $sigMethod->getAttribute('Algorithm');
 
-		if ($key->type === XMLSecurityKey::RSA_SHA1) {
-			switch ($algo) {
-				case XMLSecurityKey::RSA_SHA256:
-					$key = self::castKey($key, XMLSecurityKey::RSA_SHA256);
-					break;
-				case XMLSecurityKey::RSA_SHA384:
-					$key = self::castKey($key, XMLSecurityKey::RSA_SHA384);
-					break;
-				case XMLSecurityKey::RSA_SHA512:
-					$key = self::castKey($key, XMLSecurityKey::RSA_SHA512);
-					break;
-			}
+		if ($key->type === XMLSecurityKey::RSA_SHA1 && $algo !== $key->type) {
+			$key = self::castKey($key, $algo);
 		}
 
 		/* Check the signature. */
diff --git a/modules/saml/lib/Message.php b/modules/saml/lib/Message.php
index 6e90d65ce..64c06da13 100644
--- a/modules/saml/lib/Message.php
+++ b/modules/saml/lib/Message.php
@@ -21,7 +21,11 @@ class sspmod_saml_Message {
 
 		$keyArray = SimpleSAML_Utilities::loadPrivateKey($srcMetadata, TRUE);
 		$certArray = SimpleSAML_Utilities::loadPublicKey($srcMetadata, FALSE);
-		$algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA1);
+
+		$algo = $dstMetadata->getString('signature.algorithm', NULL);
+		if ($algo === NULL) {
+			$algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA1);
+		}
 
 		$privateKey = new XMLSecurityKey($algo, array('type' => 'private'));
 		if (array_key_exists('password', $keyArray)) {
-- 
GitLab