From 69577b3b9a2397784c8a183f6c6ef7340b5b8a59 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Wed, 4 Aug 2010 11:19:08 +0000
Subject: [PATCH] Add peer certificate validation to SoapClient.

This commit introduces a new idpMetadata parameter to SoapClient::send,
which is used to check peer certificate. If this parameter is present,
but no certData is set, an Exception will be raised.

Thanks to Adam Lantos for providing this patch.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2475 44740490-163a-0410-bde0-09ae8108e29a
---
 lib/SAML2/SOAPClient.php | 41 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 39 insertions(+), 2 deletions(-)

diff --git a/lib/SAML2/SOAPClient.php b/lib/SAML2/SOAPClient.php
index 773ab9a68..b9655c775 100644
--- a/lib/SAML2/SOAPClient.php
+++ b/lib/SAML2/SOAPClient.php
@@ -16,9 +16,10 @@ class SAML2_SOAPClient {
 	 *
 	 * @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) {
+	public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL) {
 
 		$issuer = $msg->getIssuer();
 
@@ -50,6 +51,40 @@ class SAML2_SOAPClient {
 			}
 		}
 
+		// do peer certificate verification
+		if ($dstMetadata !== NULL) {
+			$peerPublicKey = SimpleSAML_Utilities::loadPublicKey($dstMetadata);
+			if ($peerPublicKey !== NULL) {
+				$certData = $peerPublicKey['PEM'];
+				$peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
+				if (!file_exists($peerCertFile)) {
+					SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
+				}
+				// create ssl context
+				$ctxOpts = array(
+					'ssl' => array(
+						'verify_peer' => TRUE,
+						'verify_depth' => 1,
+						'cafile' => $peerCertFile
+						));
+				if (isset($options['local_cert'])) {
+					$ctxOpts['ssl']['local_cert'] = $options['local_cert'];
+					unset($options['local_cert']);
+				}
+				if (isset($options['passhprase'])) {
+					$ctxOpts['ssl']['passphrase'] = $options['passphrase'];
+					unset($options['passphrase']);
+				}
+				$context = stream_context_create($ctxOpts);
+				if ($context === NULL) {
+					throw new Exception('Unable to create SSL stream context');
+				}
+				$options['stream_context'] = $context;
+			} else {
+				throw new Exception('IdP metadata was supplied, but no certData present');
+			}
+		}
+
 		$x = new SoapClient(NULL, $options);
 
 		// Add soap-envelopes
@@ -63,7 +98,9 @@ class SAML2_SOAPClient {
 
 		/* 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.');
+		}
 
 		// Convert to SAML2_Message (DOMElement)
 		$dom = new DOMDocument();
-- 
GitLab