From e2bceaefe6b4723230fd33a30e11c1c927712998 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sat, 18 Jul 2015 10:05:34 -0400
Subject: [PATCH] Support more secure hashing algorithms for auth cookie - configurable by PHP's session.hash_function (#1490403)

---
 CHANGELOG                               |    1 +
 program/lib/Roundcube/rcube_session.php |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 .htaccess                               |    1 +
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/.htaccess b/.htaccess
index 95e5bf4..c584ac0 100644
--- a/.htaccess
+++ b/.htaccess
@@ -17,6 +17,7 @@
 php_flag    suhosin.session.encrypt     Off
 
 #php_value   session.cookie_path     /
+#php_value   session.hash_function   sha256
 php_flag    session.auto_start       Off
 php_value   session.gc_maxlifetime   21600
 php_value   session.gc_divisor       500
diff --git a/CHANGELOG b/CHANGELOG
index 7847106..76153fe 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Support more secure hashing algorithms for auth cookie - configurable by PHP's session.hash_function (#1490403)
 - Require Mbstring and OpenSSL extensions (#1490415)
 - Get rid of Mail_mimeDecode package dependency (#1490416)
 - Add --config and --type options to moduserprefs.sh script (#1490051)
diff --git a/program/lib/Roundcube/rcube_session.php b/program/lib/Roundcube/rcube_session.php
index 2d26ad6..86316f9 100644
--- a/program/lib/Roundcube/rcube_session.php
+++ b/program/lib/Roundcube/rcube_session.php
@@ -628,15 +628,66 @@
     }
 
     /**
-     * Create session cookie from session data
+     * Create session cookie from session data.
+     * The cookie will be hashed using a method defined by session.hash_function.
      *
      * @param int Time slot to use
+     *
      * @return string
      */
-    function _mkcookie($timeslot)
+    protected function _mkcookie($timeslot)
     {
         $auth_string = "$this->key,$this->secret,$timeslot";
-        return "S" . (function_exists('sha1') ? sha1($auth_string) : md5($auth_string));
+        $hash_method = (string) ini_get('session.hash_function');
+        $hash_nbits  = (int) ini_get('session.hash_bits_per_character');
+
+        if (!$hash_method) {
+            $hash_method = 'md5';
+        }
+        else if ($hash_method === '1') {
+            $hash_method = 'sha1';
+        }
+
+        if ($hash_nbits < 4 || $hash_nbits > 6) {
+            $hash_nbits = 4;
+        }
+
+        // Hash the authentication string
+        $hash = openssl_digest($auth_string, $hash_method, true);
+
+        // Above method returns "hexits". To be really compatible
+        // with session hashes generated by PHP core we'll get
+        // a raw (binary) hash and convert it to a readable form
+        // as in bin_to_readable() function in ext/session/session.c.
+        $hextab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-";
+        $length = strlen($hash);
+        $result = '';
+        $char   = 0;
+        $i      = 0;
+        $have   = 0;
+        $mask   = (1 << $hash_nbits) - 1;
+
+        while (true) {
+            if ($have < $hash_nbits) {
+                if ($i < $length) {
+                    $char |= ord($hash[$i++]) << $have;
+                    $have += 8;
+                }
+                else if (!$have) {
+                    break;
+                }
+                else {
+                    $have = $hash_nbits;
+                }
+            }
+
+            // consume nbits
+            $result .= $hextab[$char & $mask];
+            $char >>= $hash_nbits;
+            $have -= $hash_nbits;
+        }
+
+        return $result;
     }
 
     /**

--
Gitblit v1.9.1