CRAM-MD5 / DIGEST-MD5 patch for sieve-php.lib

Scott Russell lnxgeek at us.ibm.com
Wed Sep 25 11:47:35 EDT 2002


Greets.

The attached patch provides CRAM-MD5 and DIGEST-MD5 support for
sieve-php.lib. It should apply clean against the current 0.0.9
version. The patch requires the php mhash extension found at
http://mhash.sf.net/

Kudos to Dan for his sieve-php.lib class.

-- 
  Scott Russell (lnxgeek at us.ibm.com)
  Linux Technology Center, System Admin, RHCE.
  Dial 877-735-8200 then ask for 919-543-9289 (TTY)

-------------- next part --------------
--- sieve-php.lib.orig	Thu Jan 31 19:48:40 2002
+++ sieve-php.lib	Sun Sep 22 20:03:32 2002
@@ -489,6 +489,82 @@
                return false;
              $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
+	     // requires php mhash extension
+	     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(mhash(MHASH_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 = mhash(MHASH_MD5, $string_a1);
+	     $A1 = $string_a1.":".$result['nonce'].":".$cnonce.":".utf8_encode($this->auth);
+	     $A1 = bin2hex(mhash(MHASH_MD5, $A1));
+	     $A2 = bin2hex(mhash(MHASH_MD5, "AUTHENTICATE:$digest_uri_value"));
+	     $string_response = $result['nonce'].":".$ncount.":".$cnonce.":".$qop_value;
+	     $response_value = bin2hex(mhash(MHASH_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(mhash(MHASH_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;
 
         default:
@@ -503,6 +579,18 @@
 
 }
 
-
+function decode_challenge ($input) {
+    // 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
+    $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;
+}
 
 ?>


More information about the Info-cyrus mailing list