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 {
while (pktin.type == SSH1_SMSG_FAILURE) {
static char password[100];
+ static char prompt[200];
static int pos;
static char c;
static int pwpkt_type;
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
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) {
}
}
c_write("\r\n", 2);
-
- }
+ }
tryauth:
if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
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) {
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);
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++)
/*
- * 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];
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.
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 */
+}
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
*/
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;
}