mango r186 - in trunk: . lib



Author: ovitters
Date: Mon Jun  2 18:51:38 2008
New Revision: 186
URL: http://svn.gnome.org/viewvc/mango?rev=186&view=rev

Log:
	* lib/util.php: Parse the SSH public key data to determine the real
	bit length. Change the is_valid_ssh_pub_key function to give more
	feedback (array instead of just 'false').
	* lib/account.php: Adapt to is_valid_ssh_pub_key return changes.
	* lib/user.php: Adapt to is_valid_ssh_pub_key return changes.



Modified:
   trunk/ChangeLog
   trunk/lib/account.php
   trunk/lib/user.php
   trunk/lib/util.php

Modified: trunk/lib/account.php
==============================================================================
--- trunk/lib/account.php	(original)
+++ trunk/lib/account.php	Mon Jun  2 18:51:38 2008
@@ -204,7 +204,8 @@
             $error[] = 'keys';
         } else {
             foreach($this->authorizationkeys as $authorizedKey) {
-                if (!is_valid_ssh_pub_key($authorizedKey)) {
+                $l = is_valid_ssh_pub_key($authorizedKey);
+                if (!$l[0]) {
                     $error[] = 'keys';
                     break;
                 }

Modified: trunk/lib/user.php
==============================================================================
--- trunk/lib/user.php	(original)
+++ trunk/lib/user.php	Mon Jun  2 18:51:38 2008
@@ -306,9 +306,9 @@
         foreach($keys as $key) {
             $keychanges['authorizedKey'][] = $key;
 
-            $fingerprint = is_valid_ssh_pub_key($key, False, True);
-            if ($fingerprint !== false) {
-                $changes[] = array('id'=>$desc_key, "key"=>$key, "fingerprint"=>$fingerprint);
+            $ssh = is_valid_ssh_pub_key($key, False, True);
+            if ($ssh[0] !== false) {
+                $changes[] = array('id'=>$desc_key, "key"=>$key, "fingerprint"=>"$ssh[1] $ssh[2] $ssh[3] $ssh[4]");
             } else {
                 $changes[] = array('id'=>$desc_key, "key"=>$key);
             }
@@ -454,9 +454,9 @@
         $node->appendChild($dom->createTextNode($this->description));
         foreach($this->authorizedKeys as $authorizedKey) {
             $node = $formnode->appendChild($dom->createElement("authorizedKey"));
-            $fingerprint = is_valid_ssh_pub_key($authorizedKey, False, True);
-            if ($fingerprint !== false) {
-                $node->setAttribute("fingerprint", $fingerprint);
+            $ssh = is_valid_ssh_pub_key($authorizedKey, False, True);
+            if ($ssh[0] !== false) {
+                $node->setAttribute("fingerprint", "$ssh[1] $ssh[2] $ssh[3] $ssh[4]");
             }
             $node->appendChild($dom->createTextNode($authorizedKey));
         }
@@ -478,9 +478,10 @@
             $errors[] = "mail";
         
         foreach($this->authorizedKeys as $authorizedKey) {
-            if (!is_valid_ssh_pub_key($authorizedKey)) {
-            $errors[] = 'keys';
-            break;
+            $ssh = is_valid_ssh_pub_key($authorizedKey);
+            if (!$ssh[0]) {
+                $errors[] = 'keys';
+                break;
             }
         }
 

Modified: trunk/lib/util.php
==============================================================================
--- trunk/lib/util.php	(original)
+++ trunk/lib/util.php	Mon Jun  2 18:51:38 2008
@@ -3,38 +3,111 @@
 require_once('Mail.php');
 require_once('Mail/mime.php');
 
+class SSHMessage {
+
+    private
+        $idx,
+        $data_len,
+        $data;
+
+    function __construct($data) {
+        $this->idx = 0;
+        $this->data = $data;
+        $this->data_len = strlen($data);
+    }
+
+    function _get_bytes($nr) {
+        if (($this->idx + $nr) > $this->data_len)
+            throw Exception('Not enough bytes available in SSH message');
+
+        $this->idx += $nr;
+        return substr($this->data, $this->idx - $nr, $nr);
+    }
+
+    function get_int() {
+        # XXX - Weird
+        $arr = unpack('N', $this->_get_bytes(4));
+        return $arr[1];
+    }
+
+    function get_string() {
+        return $this->_get_bytes($this->get_int());
+    }
+}
+
+function bit_length($data) {
+    $hbyte = ord($data[0]);
+    $bitlen = strlen($data) * 8;
+    $check = 0x80;
+    while ($check && !($hbyte & $check)) {
+        $check >>= 1;
+        $bitlen -= 1;
+    }
+    return $bitlen;
+}
+
+
 function is_valid_ssh_pub_key($key, $check_length = True, $return_fingerprint = false) {
+    $keytype = '';
+    $length = 0;
+    $hash = '';
+    $comment = '';
+
     if(empty($key) || substr($key, 0, 4) != "ssh-")
-        return false;
+        return array(false, $keytype, $length, $hash, $comment);
 
     # Split the data
     list($format, $data, $comment) = explode(" ", $key, 3);
 
     # Format should be DSA or RSA
     if ($format != "ssh-dss" && $format != "ssh-rsa")
-        return false;
+        return array(false, $keytype, $length, $hash, $comment);
+
+    $keytype = $format == 'ssh-dss' ? 'DSA' : 'RSA';
 
     # Data should be a base64 encoded string
     $certificate = base64_decode($data);
     if ($certificate == $data)
-        return false;
+        return array(false, $keytype, $length, $hash, $comment);
+
+    $hash = rtrim(chunk_split(md5($certificate), 2, ':'), ':');
+
+    if ($check_length or $return_fingerprint) {
+        try {
+            $msg = new SSHMessage($certificate);
+            $type = $msg->get_string();
+
+            if ($type != $format)
+                return array(false, $keytype, $length, $hash, $comment);
+
+            if ($format == 'ssh-rsa') {
+                $e = $msg->get_string();
+                $n = $msg->get_string();
+                $length = bit_length($n);
+            }
+            else {
+                $p = $msg->get_string();
+                $q = $msg->get_string();
+                $g = $msg->get_string();
+                $y = $msg->get_string();
+                $length = bit_length($p);
+            }
+        } catch (Exception $e) {
+            return array(false, $keytype, $length, $hash, $comment);
+        }
+    }
 
     if ($check_length) {
-        # DSA certificate data is exactly 433 bytes (always 1024 bits, comparable to 1536 RSA key, has 305 of other data)
-        # RSA has to be >= 277 bytes (2048 bits, 21 bytes of other data)
-        #
-        # However, old ssh-keugen versions allowed DSA keys with != 1024 bits...
-        $cert_length = strlen($certificate);
-        if (($format == "ssh-dss" && $cert_length < 433)
-            || ($format == "ssh-rsa" && $cert_length < 277))
+        if (($format == "ssh-dss" && $length != 1024)
+            || ($format == "ssh-rsa" && $length < 2048))
         {
             # Either invalid, or not enough bits in the public key
-            return false;
+            return array(false, $keytype, $length, $hash, $comment);
         }
     }
 
     # All seems ok
-    return $return_fingerprint ? rtrim(chunk_split(md5($certificate), 2, ':'), ':') . ' ' . $comment : true;
+    return array(true, $keytype, $length, $hash, $comment);
 }
 
 function array_same($array1, $array2) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]