notices.digest_sasl_client.inc 3.72 KB
Newer Older
Ad Schellevis's avatar
Ad Schellevis committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
<?php
/*
 * digest_sasl_client.php
 *
 * @(#) $Id: digest_sasl_client.php,v 1.1 2005/10/27 05:24:15 mlemos Exp $
 *
 */

define('SASL_DIGEST_STATE_START',             0);
define('SASL_DIGEST_STATE_RESPOND_CHALLENGE', 1);
define('SASL_DIGEST_STATE_DONE',              2);

class digest_sasl_client_class
{
	var $credentials=array();
	var $state=SASL_DIGEST_STATE_START;

	Function unq($string)
	{
		return(($string[0]=='"' && $string[strlen($string)-1]=='"') ? substr($string, 1, strlen($string)-2) : $string);
	}

	Function H($data)
	{
		return md5($data);
	}

	Function KD($secret, $data)
	{
		return $this->H($secret.':'.$data);
	}

	Function Initialize(&$client)
	{
		return(1);
	}

	Function Start(&$client, &$message, &$interactions)
	{
		if($this->state!=SASL_DIGEST_STATE_START)
		{
			$client->error='Digest authentication state is not at the start';
			return(SASL_FAIL);
		}
		$this->credentials=array(
			'user'=>'',
			'password'=>'',
			'uri'=>'',
			'method'=>'',
			'session'=>''
		);
		$defaults=array();
		$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
		if($status==SASL_CONTINUE)
			$this->state=SASL_DIGEST_STATE_RESPOND_CHALLENGE;
		Unset($message);
		return($status);
	}

	Function Step(&$client, $response, &$message, &$interactions)
	{
		switch($this->state)
		{
			case SASL_DIGEST_STATE_RESPOND_CHALLENGE:
				$values=explode(',',$response);
				$parameters=array();
				for($v=0; $v<count($values); $v++)
					$parameters[strtok(trim($values[$v]), '=')]=strtok('');

				$message='username="'.$this->credentials['user'].'"';
				if(!IsSet($parameters[$p='realm'])
				&& !IsSet($parameters[$p='nonce']))
				{
					$client->error='Digest authentication parameter '.$p.' is missing from the server response';
					return(SASL_FAIL);
				}
				$message.=', realm='.$parameters['realm'];
				$message.=', nonce='.$parameters['nonce'];
				$message.=', uri="'.$this->credentials['uri'].'"';
				if(IsSet($parameters['algorithm']))
				{
					$algorithm=$this->unq($parameters['algorithm']);
					$message.=', algorithm='.$parameters['algorithm'];
				}
				else
					$algorithm='';

				$realm=$this->unq($parameters['realm']);
				$nonce=$this->unq($parameters['nonce']);
				if(IsSet($parameters['qop']))
				{
					switch($qop=$this->unq($parameters['qop']))
					{
						case "auth":
							$cnonce=$this->credentials['session'];
							break;
						default:
							$client->error='Digest authentication quality of protection '.$qop.' is not yet supported';
							return(SASL_FAIL);
					}
				}
				$nc_value='00000001';
				if(IsSet($parameters['qop'])
				&& !strcmp($algorithm, 'MD5-sess'))
					$A1=$this->H($this->credentials['user'].':'. $realm.':'. $this->credentials['password']).':'.$nonce.':'.$cnonce;
				else
					$A1=$this->credentials['user'].':'. $realm.':'. $this->credentials['password'];
				$A2=$this->credentials['method'].':'.$this->credentials['uri'];
				if(IsSet($parameters['qop']))
					$response=$this->KD($this->H($A1), $nonce.':'. $nc_value.':'. $cnonce.':'. $qop.':'. $this->H($A2));
				else
					$response=$this->KD($this->H($A1), $nonce.':'. $this->H($A2));
				$message.=', response="'.$response.'"';
				if(IsSet($parameters['opaque']))
					$message.=', opaque='.$parameters['opaque'];
				if(IsSet($parameters['qop']))
					$message.=', qop="'.$qop.'"';
				$message.=', nc='.$nc_value;
				if(IsSet($parameters['qop']))
					$message.=', cnonce="'.$cnonce.'"';
				$client->encode_response=0;
				$this->state=SASL_DIGEST_STATE_DONE;
				break;
			case SASL_DIGEST_STATE_DONE:
				$client->error='Digest authentication was finished without success';
				return(SASL_FAIL);
			default:
				$client->error='invalid Digest authentication step state';
				return(SASL_FAIL);
		}
		return(SASL_CONTINUE);
	}
};

135
?>