Rationalise ordering of authentication operations. Still some work to do,
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 25 Sep 2000 10:14:53 +0000 (10:14 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 25 Sep 2000 10:14:53 +0000 (10:14 +0000)
but at least pscp no longer hangs when prompting for a passphrase

git-svn-id: svn://svn.tartarus.org/sgt/putty@621 cda61777-01e9-0310-a592-d414129be87e

pageant.c
ssh.c
ssh.h
sshbn.c
sshpubk.c
sshrsa.c

index 7133c8d..978751a 100644 (file)
--- a/pageant.c
+++ b/pageant.c
@@ -127,7 +127,8 @@ void add_keyfile(char *filename) {
     int ret;
     int attempts;
 
-    needs_pass = rsakey_encrypted(filename);
+    /* FIXME: we can acquire comment here and use it in dialog */
+    needs_pass = rsakey_encrypted(filename, NULL);
     attempts = 0;
     key = malloc(sizeof(*key));
     do {
diff --git a/ssh.c b/ssh.c
index 97c6839..4068aa7 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1273,6 +1273,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
 
     while (pktin.type == SSH1_SMSG_FAILURE) {
        static char password[100];
+       static char prompt[200];
        static int pos;
        static char c;
         static int pwpkt_type;
@@ -1385,10 +1386,71 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
         if (*cfg.keyfile && !tried_publickey)
             pwpkt_type = SSH1_CMSG_AUTH_RSA;
 
-       if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD &&
-            !(flags & FLAG_INTERACTIVE)) {
-           char prompt[200];
-           sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
+        if (pktin.type == SSH1_SMSG_FAILURE &&
+            cfg.try_tis_auth &&
+            (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
+            pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
+            logevent("Requested TIS authentication");
+            send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
+            crWaitUntil(ispkt);
+            if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
+                logevent("TIS authentication declined");
+                if (flags & FLAG_INTERACTIVE)
+                    c_write("TIS authentication refused.\r\n", 29);
+            } else {
+                int challengelen = ((pktin.body[0] << 24) |
+                                    (pktin.body[1] << 16) |
+                                    (pktin.body[2] << 8) |
+                                    (pktin.body[3]));
+                logevent("Received TIS challenge");
+                if (challengelen > sizeof(prompt)-1)
+                    challengelen = sizeof(prompt)-1;   /* prevent overrun */
+                memcpy(prompt, pktin.body+4, challengelen);
+                prompt[challengelen] = '\0';
+            }
+        }
+        if (pktin.type == SSH1_SMSG_FAILURE &&
+            cfg.try_tis_auth &&
+            (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
+            pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
+            logevent("Requested CryptoCard authentication");
+            send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
+            crWaitUntil(ispkt);
+            if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
+                logevent("CryptoCard authentication declined");
+                c_write("CryptoCard authentication refused.\r\n", 29);
+            } else {
+                int challengelen = ((pktin.body[0] << 24) |
+                                    (pktin.body[1] << 16) |
+                                    (pktin.body[2] << 8) |
+                                    (pktin.body[3]));
+                logevent("Received CryptoCard challenge");
+                if (challengelen > sizeof(prompt)-1)
+                    challengelen = sizeof(prompt)-1;   /* prevent overrun */
+                memcpy(prompt, pktin.body+4, challengelen);
+                strncpy(prompt + challengelen, "\r\nResponse : ",
+                        sizeof(prompt)-challengelen);
+                prompt[sizeof(prompt)-1] = '\0';
+            }
+        }
+        if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
+            sprintf(prompt, "%.90s@%.90s's password: ",
+                    cfg.username, savedhost);
+        }
+        if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
+            char *comment = NULL;
+            if (flags & FLAG_VERBOSE)
+                c_write("Trying public key authentication.\r\n", 35);
+            if (!rsakey_encrypted(cfg.keyfile, &comment)) {
+                if (flags & FLAG_VERBOSE)
+                    c_write("No passphrase required.\r\n", 25);
+                goto tryauth;
+            }
+            sprintf(prompt, "Passphrase for key \"%.100s\": ", comment);
+            free(comment);
+        }
+
+       if (!(flags & FLAG_INTERACTIVE)) {
            if (!ssh_get_password(prompt, password, sizeof(password))) {
                 /*
                  * get_password failed to get a password (for
@@ -1401,59 +1463,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                 crReturn(1);
             }
        } else {
-
-            if (pktin.type == SSH1_SMSG_FAILURE &&
-                cfg.try_tis_auth &&
-                (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
-                pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
-                logevent("Requested TIS authentication");
-                send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
-                crWaitUntil(ispkt);
-                if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
-                    logevent("TIS authentication declined");
-                    c_write("TIS authentication refused.\r\n", 29);
-                } else {
-                    int challengelen = ((pktin.body[0] << 24) |
-                                        (pktin.body[1] << 16) |
-                                        (pktin.body[2] << 8) |
-                                        (pktin.body[3]));
-                    logevent("Received TIS challenge");
-                    c_write(pktin.body+4, challengelen);
-                }
-            }
-            if (pktin.type == SSH1_SMSG_FAILURE &&
-                cfg.try_tis_auth &&
-                (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
-                pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
-                logevent("Requested CryptoCard authentication");
-                send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
-                crWaitUntil(ispkt);
-                if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
-                    logevent("CryptoCard authentication declined");
-                    c_write("CryptoCard authentication refused.\r\n", 29);
-                } else {
-                    int challengelen = ((pktin.body[0] << 24) |
-                                        (pktin.body[1] << 16) |
-                                        (pktin.body[2] << 8) |
-                                        (pktin.body[3]));
-                    logevent("Received CryptoCard challenge");
-                    c_write(pktin.body+4, challengelen);
-                    c_write("\r\nResponse : ", 13);
-                }
-            }
-            if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD)
-                c_write("password: ", 10);
-            if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
-                if (flags & FLAG_VERBOSE)
-                    c_write("Trying public key authentication.\r\n", 35);
-                if (!rsakey_encrypted(cfg.keyfile)) {
-                    if (flags & FLAG_VERBOSE)
-                        c_write("No passphrase required.\r\n", 25);
-                    goto tryauth;
-                }
-                c_write("passphrase: ", 12);
-            }
-
+            c_write(prompt, strlen(prompt));
             pos = 0;
             ssh_send_ok = 1;
             while (pos >= 0) {
@@ -1482,8 +1492,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                 }
             }
             c_write("\r\n", 2);
-
-       }
+        }
 
         tryauth:
        if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
@@ -1518,8 +1527,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
 
             crWaitUntil(ispkt);
             if (pktin.type == SSH1_SMSG_FAILURE) {
-                if (flags & FLAG_VERBOSE)
-                    c_write("Server refused our public key.\r\n", 32);
+                c_write("Server refused our public key.\r\n", 32);
                 continue;              /* go and try password */
             }
             if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
diff --git a/ssh.h b/ssh.h
index a2b6401..058c524 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -156,7 +156,7 @@ Bignum dh_create_e(void);
 Bignum dh_find_K(Bignum f);
 
 int loadrsakey(char *filename, struct RSAKey *key, char *passphrase);
-int rsakey_encrypted(char *filename);
+int rsakey_encrypted(char *filename, char **comment);
 
 void des3_decrypt_pubkey(unsigned char *key,
                          unsigned char *blk, int len);
diff --git a/sshbn.c b/sshbn.c
index adb8824..dbf223d 100644 (file)
--- a/sshbn.c
+++ b/sshbn.c
@@ -324,6 +324,9 @@ int ssh1_read_bignum(unsigned char *data, Bignum *result) {
     b = (w+7)/8;                       /* bits -> bytes */
     w = (w+15)/16;                    /* bits -> words */
 
+    if (!result)                       /* just return length */
+        return b + 2;
+
     bn = newbn(w);
 
     for (i=1; i<=w; i++)
index 3e4de1f..fb5b7cc 100644 (file)
--- a/sshpubk.c
+++ b/sshpubk.c
@@ -1,17 +1,17 @@
 /*
- * Read SSH public keys from files.
- *
- * First implementation: only supports unencrypted SSH 1.1 format
- * RSA keys. Encryption, and SSH 2 DSS keys, to be supported later.
+ * Generic SSH public-key handling operations. In particular,
+ * reading of SSH public-key files, and also the generic `sign'
+ * operation for ssh2 (which checks the type of the key and
+ * dispatches to the appropriate key-type specific function).
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 
-#include <stdio.h> /* FIXME */
 #include <stdarg.h> /* FIXME */
 #include <windows.h> /* FIXME */
-#include "putty.h" /* FIXME */
 
+#include "putty.h"
 #include "ssh.h"
 
 #define GET_32BIT(cp) \
     ((unsigned long)(unsigned char)(cp)[3]))
 
 #define rsa_signature "SSH PRIVATE KEY FILE FORMAT 1.1\n"
+#define dss_signature "-----BEGIN DSA PRIVATE KEY-----\n"
 
-int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) {
-    FILE *fp;
+#define BASE64_TOINT(x) ( (x)-'A'<26 ? (x)-'A'+0 :\
+                          (x)-'a'<26 ? (x)-'a'+26 :\
+                          (x)-'0'<10 ? (x)-'0'+52 :\
+                          (x)=='+' ? 62 : \
+                          (x)=='/' ? 63 : 0 )
+
+static int loadrsakey_main(FILE *fp, struct RSAKey *key,
+                           char **commentptr, char *passphrase) {
     unsigned char buf[16384];
     unsigned char keybuf[16];
     int len;
     int i, j, ciphertype;
     int ret = 0;
     struct MD5Context md5c;
+    char *comment;
 
-    fp = fopen(filename, "rb");
-    if (!fp)
-        goto end;
-
-    /* Slurp the whole file into a buffer. */
+    /* Slurp the whole file (minus the header) into a buffer. */
     len = fread(buf, 1, sizeof(buf), fp);
     fclose(fp);
     if (len < 0 || len == sizeof(buf))
         goto end;                      /* file too big or not read */
 
-    if (len < sizeof(rsa_signature) ||
-        memcmp(buf, rsa_signature, sizeof(rsa_signature)) != 0)
-        goto end;                      /* failure to have sig at front */
+    i = 0;
 
-    i = sizeof(rsa_signature);
+    /*
+     * A zero byte. (The signature includes a terminating NUL.)
+     */
+    if (len-i < 1 || buf[i] != 0)
+        goto end;
+    i++;
 
-    /* Next, one byte giving encryption type, and one reserved uint32. */
+    /* One byte giving encryption type, and one reserved uint32. */
     if (len-i < 1)
         goto end;
     ciphertype = buf[i];
@@ -69,12 +76,19 @@ int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) {
     j = GET_32BIT(buf+i);
     i += 4;
     if (len-i < j) goto end;
-    key->comment = malloc(j+1);
-    if (key->comment) {
-        memcpy(key->comment, buf+i, j);
-        key->comment[j] = '\0';
+    comment = malloc(j+1);
+    if (comment) {
+        memcpy(comment, buf+i, j);
+        comment[j] = '\0';
     }
     i += j;
+    if (commentptr)
+        *commentptr = comment;
+    if (key)
+        key->comment = comment;
+    if (!key) {
+        return ciphertype != 0;
+    }
 
     /*
      * Decrypt remainder of buffer.
@@ -108,24 +122,49 @@ int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) {
     return ret;
 }
 
-/*
- * See whether an RSA key is encrypted.
- */
-int rsakey_encrypted(char *filename) {
+int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) {
     FILE *fp;
-    unsigned char buf[1+sizeof(rsa_signature)];
-    int len;
+    unsigned char buf[64];
 
     fp = fopen(filename, "rb");
     if (!fp)
         return 0;                      /* doesn't even exist */
 
-    /* Slurp the whole file into a buffer. */
-    len = fread(buf, 1, sizeof(buf), fp);
+    /*
+     * Read the first line of the file and see if it's a v1 private
+     * key file.
+     */
+    if (fgets(buf, sizeof(buf), fp) &&
+        !strcmp(buf, rsa_signature)) {
+        return loadrsakey_main(fp, key, NULL, passphrase);
+    }
+
+    /*
+     * Otherwise, we have nothing. Return empty-handed.
+     */
     fclose(fp);
-    if (len < sizeof(buf))
-        return 0;                      /* not even valid */
-    if (buf[sizeof(buf)-1])
-        return 1;                      /* encrypted */
     return 0;
 }
+
+/*
+ * See whether an RSA key is encrypted. Return its comment field as
+ * well.
+ */
+int rsakey_encrypted(char *filename, char **comment) {
+    FILE *fp;
+    unsigned char buf[64];
+
+    fp = fopen(filename, "rb");
+    if (!fp)
+        return 0;                      /* doesn't even exist */
+
+    /*
+     * Read the first line of the file and see if it's a v1 private
+     * key file.
+     */
+    if (fgets(buf, sizeof(buf), fp) &&
+        !strcmp(buf, rsa_signature)) {
+        return loadrsakey_main(fp, NULL, comment, NULL);
+    }
+    return 0;                          /* wasn't the right kind of file */
+}
index e44dce8..324fbd1 100644 (file)
--- a/sshrsa.c
+++ b/sshrsa.c
@@ -43,9 +43,12 @@ int makekey(unsigned char *data, struct RSAKey *result,
     unsigned char *p = data;
     int i;
 
-    result->bits = 0;
-    for (i=0; i<4; i++)
-       result->bits = (result->bits << 8) + *p++;
+    if (result) {
+        result->bits = 0;
+        for (i=0; i<4; i++)
+            result->bits = (result->bits << 8) + *p++;
+    } else
+        p += 4;
 
     /*
      * order=0 means exponent then modulus (the keys sent by the
@@ -54,12 +57,13 @@ int makekey(unsigned char *data, struct RSAKey *result,
      */
 
     if (order == 0)
-        p += ssh1_read_bignum(p, &result->exponent);
-    result->bytes = (((p[0] << 8) + p[1]) + 7) / 8;
+        p += ssh1_read_bignum(p, result ? &result->exponent : NULL);
+    if (result)
+        result->bytes = (((p[0] << 8) + p[1]) + 7) / 8;
     if (keystr) *keystr = p+2;
-    p += ssh1_read_bignum(p, &result->modulus);
+    p += ssh1_read_bignum(p, result ? &result->modulus : NULL);
     if (order == 1)
-        p += ssh1_read_bignum(p, &result->exponent);
+        p += ssh1_read_bignum(p, result ? &result->exponent : NULL);
 
     return p - data;
 }