Bugtraq mailing list archives

Re: SSH1 key recovery patch


From: Johannes Geiger <geiger () SUNSPIES8 INFORMATIK TU-MUENCHEN DE>
Date: Tue, 20 Feb 2001 12:48:09 +0100

Hello!

On Wed, Feb 14, 2001 at 05:35:13AM +0100, Iván Arce wrote:
 In light of the recent posts to bugtraq concerning the
 CORE SDI advisory that describes the SSH1 session
 key recovery vulnerability a few things needs to be
 noted:
(...)
 The rationale for the above fix is to regenerate the key whenever
 a RSA operation failed - a symptom of an attacker trying to
 execute the key recovery attack- this does not close the information
 leakage in the ssh server (namely the existence of an oracle that can
 be used to infer a session key) but it does make IMPOSSIBLE to
 exploit it.

 The patch intends to limit the key regeneration rate to
 at most one regeneration per minute, in order to prevent
 a DoS.
(...)

Wouldn't it be much easier and less error prone to actually disable the
oracle, which is the real problem leading to the attack, instead of all
this key regeneration stuff?

quote from the original attack description:
  Notice that the calls to the function fatal() can be used as the
  needed oracle.
  Successful negotiation of  a session key will end with
  the reception of a SSH_SMSG_SUCCESS packet at the client. A failure
  will end with the connection being shutdown due to the calls to the
  fatal() function from within the rash_private_decrypt() function.

So all you have to do is to always do both RSA operations, record a
failure of the first but call fatal() only after the second. Or did I
miss something?

Regards

Johannes



The following patch is UNTESTED and supplied only to make myself clear.

--- rsaglue.c.orig      Tue Feb 20 11:20:21 2001
+++ rsaglue.c   Tue Feb 20 11:23:21 2001
@@ -238,11 +238,12 @@

 /* Decrypt input using the private key.  Output will become a 256 bit value. */

-void rsa_private_decrypt(MP_INT *output, MP_INT *input, RSAPrivateKey *key)
+int rsa_private_decrypt(MP_INT *output, MP_INT *input, RSAPrivateKey *key)
 {
   MP_INT aux;
   unsigned int len, i;
   unsigned char *value;
+  int success;

   rsa_private(output, input, key);

@@ -263,8 +264,7 @@
     }
   mpz_clear(&aux);

-  if (value[0] != 0 || value[1] != 2)
-    fatal("Bad result from rsa_private_decrypt");
+  success == (value[0] == 0 && value[1] == 2);

   for (i = 2; i < len && value[i]; i++)
     ;
@@ -272,6 +272,9 @@
   xfree(value);

   mpz_mod_2exp(output, output, 8 * (len - i - 1));
+
+  return success;
+
 }

 #endif /* RSAREF */
--- rsa.h.orig  Tue Feb 20 11:38:04 2001
+++ rsa.h       Tue Feb 20 12:21:50 2001
@@ -111,6 +111,6 @@
                         RandomState *state);

 /* Performs a private key decrypt operation. */
-void rsa_private_decrypt(MP_INT *output, MP_INT *input, RSAPrivateKey *key);
+int rsa_private_decrypt(MP_INT *output, MP_INT *input, RSAPrivateKey *key);

 #endif /* RSA_H */
--- sshd.c.orig Tue Feb 20 11:20:12 2001
+++ sshd.c      Tue Feb 20 12:43:54 2001
@@ -1553,23 +1553,29 @@
      larger modulus first). */
   if (mpz_cmp(&sensitive_data.private_key.n, &sensitive_data.host_key.n) > 0)
     {
+      int rok1, rok2;
       /* Private key has bigger modulus. */
       assert(sensitive_data.private_key.bits >=
              sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED);
-      rsa_private_decrypt(&session_key_int, &session_key_int,
-                          &sensitive_data.private_key);
-      rsa_private_decrypt(&session_key_int, &session_key_int,
-                          &sensitive_data.host_key);
+      rok1 = rsa_private_decrypt(&session_key_int, &session_key_int,
+                                &sensitive_data.private_key);
+      rok2 = rsa_private_decrypt(&session_key_int, &session_key_int,
+                                &sensitive_data.host_key);
+      if (!(rok1 && rok2))
+       fatal("Bad result from rsa_private_decrypt");
     }
   else
     {
+      int rok1, rok2;
       /* Host key has bigger modulus (or they are equal). */
       assert(sensitive_data.host_key.bits >=
              sensitive_data.private_key.bits + SSH_KEY_BITS_RESERVED);
-      rsa_private_decrypt(&session_key_int, &session_key_int,
-                          &sensitive_data.host_key);
-      rsa_private_decrypt(&session_key_int, &session_key_int,
-                          &sensitive_data.private_key);
+      rok1 = rsa_private_decrypt(&session_key_int, &session_key_int,
+                                &sensitive_data.host_key);
+      rok2 = rsa_private_decrypt(&session_key_int, &session_key_int,
+                                &sensitive_data.private_key);
+      if (!(rok1 && rok2))
+       fatal("Bad result from rsa_private_decrypt");
     }

   /* Compute session id for this session. */


Current thread: