From: <av...@us...> - 2003-10-22 14:00:17
|
Update of /cvsroot/sieve-php/sieve-php In directory sc8-pr-cvs1:/tmp/cvs-serv6754 Modified Files: sieve-php.lib Log Message: Added DIGEST-MD5 and CRAM-MD5 code, and support functions. Changed Dan's email to the mailing list email. Index: sieve-php.lib =================================================================== RCS file: /cvsroot/sieve-php/sieve-php/sieve-php.lib,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** sieve-php.lib 22 Oct 2003 12:40:57 -0000 1.11 --- sieve-php.lib 22 Oct 2003 13:12:55 -0000 1.12 *************** *** 48,51 **** --- 48,53 ---- Andrew Sterling Hanenkamp <ste...@ha...> "Ilya Pizik" <po...@sc...> (AUTH LOGIN) + Scott Russell <ln...@us...> (DIGEST-MD5 & CRAM-MD5) + Alexandros Vellis <av...@no...> */ *************** *** 191,195 **** $this->error = EC_UNKNOWN; $this->error_raw = $this->line; ! print "<b><i>UNKNOWN ERROR (Please report this line to dan...@ru... to include in future releases): $this->line</i></b><br>"; return false; } /* end else */ --- 193,201 ---- $this->error = EC_UNKNOWN; $this->error_raw = $this->line; ! print '<b><i>UNKNOWN ERROR (Please report this line to <a ! href="mailto:sie...@li...">sieve-php-devel ! Mailing List</a> to include in future releases): ! '.$this->line.'</i></b><br>'; ! return false; } /* end else */ *************** *** 476,480 **** switch ($this->auth_in_use) { - case "PLAIN": --- 482,485 ---- *************** *** 493,496 **** --- 498,576 ---- $this->loggedin=true; return true; + break; + + case "DIGEST-MD5": + // SASL DIGEST-MD5 support works with timsieved 1.1.0 + // follows rfc2831 for generating the $response to $challenge + fputs($this->fp, "AUTHENTICATE \"DIGEST-MD5\"\r\n"); + // $clen is length of server challenge, we ignore it. + $clen = fgets($this->fp, 1024); + // read for 2048, rfc2831 max length allowed + $challenge = fgets($this->fp, 2048); + // vars used when building $response_value and $response + $cnonce = base64_encode(bin2hex(hmac_md5(microtime()))); + $ncount = "00000001"; + $qop_value = "auth"; + $digest_uri_value = "sieve/$this->host"; + // decode the challenge string + $result = decode_challenge($challenge); + // verify server supports qop=auth + $qop = explode(",",$result['qop']); + if (!in_array($qop_value, $qop)) { + // rfc2831: client MUST fail if no qop methods supported + return false; + } + // build the $response_value + $string_a1 = utf8_encode($this->user).":"; + $string_a1 .= utf8_encode($result['realm']).":"; + $string_a1 .= utf8_encode($this->pass); + $string_a1 = hmac_md5($string_a1); + $A1 = $string_a1.":".$result['nonce'].":".$cnonce.":".utf8_encode($this->auth); + $A1 = bin2hex(hmac_md5($A1)); + $A2 = bin2hex(hmac_md5("AUTHENTICATE:$digest_uri_value")); + $string_response = $result['nonce'].":".$ncount.":".$cnonce.":".$qop_value; + $response_value = bin2hex(hmac_md5($A1.":".$string_response.":".$A2)); + // build the challenge $response + $reply = "charset=utf-8,username=\"".$this->user."\",realm=\"".$result['realm']."\","; + $reply .= "nonce=\"".$result['nonce']."\",nc=$ncount,cnonce=\"$cnonce\","; + $reply .= "digest-uri=\"$digest_uri_value\",response=$response_value,"; + $reply .= "qop=$qop_value,authzid=\"".utf8_encode($this->auth)."\""; + $response = base64_encode($reply); + fputs($this->fp, "\"$response\"\r\n"); + + $this->line = fgets($this->fp, 1024); + while(sieve::status($this->line) == F_DATA) + $this->line = fgets($this->fp,1024); + + if(sieve::status($this->line) == F_NO) + return false; + $this->loggedin = TRUE; + return TRUE; + break; + + case "CRAM-MD5": + // SASL CRAM-MD5 support works with timsieved 1.1.0 + // follows rfc2195 for generating the $response to $challenge + // CRAM-MD5 does not support proxy of $auth by $user + // requires php mhash extension + fputs($this->fp, "AUTHENTICATE \"CRAM-MD5\"\r\n"); + // $clen is the length of the challenge line the server gives us + $clen = fgets($this->fp, 1024); + // read for 1024, should be long enough? + $challenge = fgets($this->fp, 1024); + // build a response to the challenge + $hash = bin2hex(hmac_md5(base64_decode($challenge), $this->pass)); + $response = base64_encode($this->user." ".$hash); + // respond to the challenge string + fputs($this->fp, "\"$response\"\r\n"); + + $this->line = fgets($this->fp, 1024); + while(sieve::status($this->line) == F_DATA) + $this->line = fgets($this->fp,1024); + + if(sieve::status($this->line) == F_NO) + return false; + $this->loggedin = TRUE; + return TRUE; break; *************** *** 532,535 **** --- 612,669 ---- + /* Support functions follow. */ + + if(!function_exists('hmac_md5')) { + + /** Creates a HMAC digest that can be used for auth purposes. + * + * Squirrelmail has this function in functions/auth.php, and it might have been + * included already. However, it helps remove the dependancy on mhash.so PHP + * extension, for some sites. If mhash.so _is_ available, it is used for its + * speed. + * + * This function is Copyright (c) 1999-2003 The SquirrelMail Project Team + * Licensed under the GNU GPL. For full terms see the file COPYING. + */ + function hmac_md5($data, $key='') { + // See RFCs 2104, 2617, 2831 + // Uses mhash() extension if available + if (extension_loaded('mhash')) { + if ($key== '') { + $mhash=mhash(MHASH_MD5,$data); + } else { + $mhash=mhash(MHASH_MD5,$data,$key); + } + return $mhash; + } + if (!$key) { + return pack('H*',md5($data)); + } + $key = str_pad($key,64,chr(0x00)); + if (strlen($key) > 64) { + $key = pack("H*",md5($key)); + } + $k_ipad = $key ^ str_repeat(chr(0x36), 64) ; + $k_opad = $key ^ str_repeat(chr(0x5c), 64) ; + /* Heh, let's get recursive. */ + $hmac=hmac_md5($k_opad . pack("H*",md5($k_ipad . $data)) ); + return $hmac; + } + } + + /** FIXME: this function is a hack to decode the challenge from timsieved + * 1.1.0. It may not work with other versions and most certainly won't work + * with other DIGEST-MD5 implentations + */ + function decode_challenge ($input) { + $input = base64_decode($input); + preg_match("/nonce=\"(.*)\"/U",$input, $matches); + $resp['nonce'] = $matches[1]; + preg_match("/realm=\"(.*)\"/U",$input, $matches); + $resp['realm'] = $matches[1]; + preg_match("/qop=\"(.*)\"/U",$input, $matches); + $resp['qop'] = $matches[1]; + return $resp; + } ?> |