The `socket' function in the backends is only ever checked to see if
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 7e18388..7c5c7bc 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1,7 +1,12 @@
+/*
+ * SSH backend.
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <assert.h>
+#include <limits.h>
 
 #include "putty.h"
 #include "tree234.h"
@@ -708,7 +713,7 @@ struct ssh_tag {
     void *cs_comp_ctx, *sc_comp_ctx;
     const struct ssh_kex *kex;
     const struct ssh_signkey *hostkey;
-    unsigned char v2_session_id[32];
+    unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN];
     int v2_session_id_len;
     void *kex_ctx;
 
@@ -3222,7 +3227,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
     while (pktin->type == SSH1_SMSG_FAILURE) {
        s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
 
-       if (agent_exists() && !s->tried_agent) {
+       if (ssh->cfg.tryagent && agent_exists() && !s->tried_agent) {
            /*
             * Attempt RSA authentication using Pageant.
             */
@@ -4964,7 +4969,10 @@ static int first_in_commasep_string(char *needle, char *haystack, int haylen)
 
 /*
  * SSH-2 key creation method.
+ * (Currently assumes 2 lots of any hash are sufficient to generate
+ * keys/IVs for any cipher/MAC. SSH2_MKKEY_ITERS documents this assumption.)
  */
+#define SSH2_MKKEY_ITERS (2)
 static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, char chr,
                       unsigned char *keyspace)
 {
@@ -5011,7 +5019,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
        char *hostkeydata, *sigdata, *keystr, *fingerprint;
        int hostkeylen, siglen;
        void *hkey;                    /* actual host key */
-       unsigned char exchange_hash[32];
+       unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN];
        int n_preferred_kex;
        const struct ssh_kexes *preferred_kex[KEX_MAX];
        int n_preferred_ciphers;
@@ -5064,7 +5072,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                s->preferred_kex[s->n_preferred_kex++] =
                    &ssh_diffiehellman_group1;
                break;
-             case CIPHER_WARN:
+             case KEX_WARN:
                /* Flag for later. Don't bother if it's the last in
                 * the list. */
                if (i < KEX_MAX - 1) {
@@ -5519,7 +5527,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                  ssh->kex->groupname);
     }
 
-    logevent("Doing Diffie-Hellman key exchange");
+    logeventf(ssh, "Doing Diffie-Hellman key exchange with hash %s",
+             ssh->kex->hash->text_name);
     /*
      * Now generate and send e for Diffie-Hellman.
      */
@@ -5661,13 +5670,21 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
      * hash from the _first_ key exchange.
      */
     {
-       unsigned char keyspace[40];
+       unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];
+       assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh2_mkkey(ssh,s->K,s->exchange_hash,'C',keyspace);
+       assert((ssh->cscipher->keylen+7) / 8 <=
+              ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh->cscipher->setkey(ssh->cs_cipher_ctx, keyspace);
        ssh2_mkkey(ssh,s->K,s->exchange_hash,'A',keyspace);
+       assert(ssh->cscipher->blksize <=
+              ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace);
        ssh2_mkkey(ssh,s->K,s->exchange_hash,'E',keyspace);
+       assert(ssh->csmac->len <=
+              ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace);
+       memset(keyspace, 0, sizeof(keyspace));
     }
 
     logeventf(ssh, "Initialised %.200s client->server encryption",
@@ -5719,13 +5736,21 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
      * hash from the _first_ key exchange.
      */
     {
-       unsigned char keyspace[40];
+       unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];
+       assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh2_mkkey(ssh,s->K,s->exchange_hash,'D',keyspace);
+       assert((ssh->sccipher->keylen+7) / 8 <=
+              ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh->sccipher->setkey(ssh->sc_cipher_ctx, keyspace);
        ssh2_mkkey(ssh,s->K,s->exchange_hash,'B',keyspace);
+       assert(ssh->sccipher->blksize <=
+              ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace);
        ssh2_mkkey(ssh,s->K,s->exchange_hash,'F',keyspace);
+       assert(ssh->scmac->len <=
+              ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
        ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace);
+       memset(keyspace, 0, sizeof(keyspace));
     }
     logeventf(ssh, "Initialised %.200s server->client encryption",
              ssh->sccipher->text_name);
@@ -6613,7 +6638,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
        s->nkeys = 0;
        s->agent_response = NULL;
        s->pkblob_in_agent = NULL;
-       if (agent_exists()) {
+       if (ssh->cfg.tryagent && agent_exists()) {
 
            void *r;
 
@@ -8700,10 +8725,10 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org)
     }
 }
 
-static Socket ssh_socket(void *handle)
+static int ssh_connected(void *handle)
 {
     Ssh ssh = (Ssh) handle;
-    return ssh->s;
+    return ssh->s != NULL;
 }
 
 static int ssh_sendok(void *handle)
@@ -8740,7 +8765,7 @@ static int ssh_return_exitcode(void *handle)
     if (ssh->s != NULL)
         return -1;
     else
-        return (ssh->exitcode >= 0 ? ssh->exitcode : 0);
+        return (ssh->exitcode >= 0 ? ssh->exitcode : INT_MAX);
 }
 
 /*
@@ -8773,7 +8798,7 @@ Backend ssh_backend = {
     ssh_size,
     ssh_special,
     ssh_get_specials,
-    ssh_socket,
+    ssh_connected,
     ssh_return_exitcode,
     ssh_sendok,
     ssh_ldisc,