functions have sprouted `**errorstr' arguments, which if non-NULL can
return a textual error message. The interface additions are patchy and
ad-hoc since this seemed to suit the style of the existing interfaces.
I've since realised that most of this is masked by sanity-checking that
gets done before these functions are called, but it will at least report
MAC failures and the like (tested on Unix), which was the original point
of the exercise.
Note that not everyone who could be using this information is at the
moment.
git-svn-id: svn://svn.tartarus.org/sgt/putty@3430
cda61777-01e9-0310-a592-
d414129be87e
int i, nkeys, bloblen;
if (type == SSH_KEYTYPE_SSH1) {
int i, nkeys, bloblen;
if (type == SSH_KEYTYPE_SSH1) {
- if (!rsakey_pubblob(&filename, &blob, &bloblen)) {
+ if (!rsakey_pubblob(&filename, &blob, &bloblen, NULL)) {
MessageBox(NULL, "Couldn't load private key.", APPNAME,
MB_OK | MB_ICONERROR);
return;
MessageBox(NULL, "Couldn't load private key.", APPNAME,
MB_OK | MB_ICONERROR);
return;
keylist = get_keylist1();
} else {
unsigned char *blob2;
keylist = get_keylist1();
} else {
unsigned char *blob2;
- blob = ssh2_userkey_loadpub(&filename, NULL, &bloblen);
+ blob = ssh2_userkey_loadpub(&filename, NULL, &bloblen, NULL);
if (!blob) {
MessageBox(NULL, "Couldn't load private key.", APPNAME,
MB_OK | MB_ICONERROR);
if (!blob) {
MessageBox(NULL, "Couldn't load private key.", APPNAME,
MB_OK | MB_ICONERROR);
} else
*passphrase = '\0';
if (type == SSH_KEYTYPE_SSH1)
} else
*passphrase = '\0';
if (type == SSH_KEYTYPE_SSH1)
- ret = loadrsakey(&filename, rkey, passphrase);
+ ret = loadrsakey(&filename, rkey, passphrase, NULL);
- skey = ssh2_load_userkey(&filename, passphrase);
+ skey = ssh2_load_userkey(&filename, passphrase, NULL);
if (skey == SSH2_WRONG_PASSPHRASE)
ret = -1;
else if (!skey)
if (skey == SSH2_WRONG_PASSPHRASE)
ret = -1;
else if (!skey)
if (type == SSH_KEYTYPE_SSH1) {
if (realtype == type)
ret = loadrsakey(&filename, &newkey1,
if (type == SSH_KEYTYPE_SSH1) {
if (realtype == type)
ret = loadrsakey(&filename, &newkey1,
else
ret = import_ssh1(&filename, realtype,
&newkey1, passphrase);
} else {
if (realtype == type)
newkey2 = ssh2_load_userkey(&filename,
else
ret = import_ssh1(&filename, realtype,
&newkey1, passphrase);
} else {
if (realtype == type)
newkey2 = ssh2_load_userkey(&filename,
else
newkey2 = import_ssh2(&filename, realtype,
passphrase);
else
newkey2 = import_ssh2(&filename, realtype,
passphrase);
/* Load the public half of ssh->cfg.keyfile so we notice if it's in Pageant */
if (!filename_is_null(ssh->cfg.keyfile)) {
if (!rsakey_pubblob(&ssh->cfg.keyfile,
/* Load the public half of ssh->cfg.keyfile so we notice if it's in Pageant */
if (!filename_is_null(ssh->cfg.keyfile)) {
if (!rsakey_pubblob(&ssh->cfg.keyfile,
- &s->publickey_blob, &s->publickey_bloblen))
+ &s->publickey_blob, &s->publickey_bloblen, NULL))
s->publickey_blob = NULL;
} else
s->publickey_blob = NULL;
s->publickey_blob = NULL;
} else
s->publickey_blob = NULL;
s->tried_publickey = 1;
{
s->tried_publickey = 1;
{
- int ret = loadrsakey(&ssh->cfg.keyfile, &s->key, s->password);
+ const char *error = NULL;
+ int ret = loadrsakey(&ssh->cfg.keyfile, &s->key, s->password,
+ &error);
if (ret == 0) {
c_write_str(ssh, "Couldn't load private key from ");
c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile));
if (ret == 0) {
c_write_str(ssh, "Couldn't load private key from ");
c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile));
- c_write_str(ssh, ".\r\n");
+ c_write_str(ssh, " (");
+ c_write_str(ssh, error);
+ c_write_str(ssh, ").\r\n");
continue; /* go and try password */
}
if (ret == -1) {
continue; /* go and try password */
}
if (ret == -1) {
if (keytype == SSH_KEYTYPE_SSH2) {
s->publickey_blob =
ssh2_userkey_loadpub(&ssh->cfg.keyfile, NULL,
if (keytype == SSH_KEYTYPE_SSH2) {
s->publickey_blob =
ssh2_userkey_loadpub(&ssh->cfg.keyfile, NULL,
- &s->publickey_bloblen);
+ &s->publickey_bloblen, NULL);
} else {
char *msgbuf;
logeventf(ssh, "Unable to use this key file (%s)",
} else {
char *msgbuf;
logeventf(ssh, "Unable to use this key file (%s)",
pub_blob =
(unsigned char *)ssh2_userkey_loadpub(&ssh->cfg.keyfile,
&algorithm,
pub_blob =
(unsigned char *)ssh2_userkey_loadpub(&ssh->cfg.keyfile,
&algorithm,
+ &pub_blob_len,
+ NULL);
if (pub_blob) {
ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(ssh, s->username);
if (pub_blob) {
ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(ssh, s->username);
* We have our passphrase. Now try the actual authentication.
*/
struct ssh2_userkey *key;
* We have our passphrase. Now try the actual authentication.
*/
struct ssh2_userkey *key;
+ const char *error = NULL;
- key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password);
+ key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password,
+ &error);
if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
if (key == SSH2_WRONG_PASSPHRASE) {
c_write_str(ssh, "Wrong passphrase\r\n");
s->tried_pubkey_config = FALSE;
} else {
if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {
if (key == SSH2_WRONG_PASSPHRASE) {
c_write_str(ssh, "Wrong passphrase\r\n");
s->tried_pubkey_config = FALSE;
} else {
- c_write_str(ssh, "Unable to load private key\r\n");
+ c_write_str(ssh, "Unable to load private key (");
+ c_write_str(ssh, error);
+ c_write_str(ssh, ")\r\n");
s->tried_pubkey_config = TRUE;
}
/* Send a spurious AUTH_NONE to return to the top. */
s->tried_pubkey_config = TRUE;
}
/* Send a spurious AUTH_NONE to return to the top. */
Bignum dh_find_K(void *, Bignum f);
int loadrsakey(const Filename *filename, struct RSAKey *key,
Bignum dh_find_K(void *, Bignum f);
int loadrsakey(const Filename *filename, struct RSAKey *key,
+ char *passphrase, const char **errorstr);
int rsakey_encrypted(const Filename *filename, char **comment);
int rsakey_encrypted(const Filename *filename, char **comment);
-int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen);
+int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
+ const char **errorstr);
int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase);
int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase);
int ssh2_userkey_encrypted(const Filename *filename, char **comment);
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
int ssh2_userkey_encrypted(const Filename *filename, char **comment);
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
+ char *passphrase, const char **errorstr);
char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
+ int *pub_blob_len, const char **errorstr);
int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
char *passphrase);
int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
char *passphrase);
(x)=='/' ? 63 : 0 )
static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
(x)=='/' ? 63 : 0 )
static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
- char **commentptr, char *passphrase)
+ char **commentptr, char *passphrase,
+ const char **error)
{
unsigned char buf[16384];
unsigned char keybuf[16];
{
unsigned char buf[16384];
unsigned char keybuf[16];
struct MD5Context md5c;
char *comment;
struct MD5Context md5c;
char *comment;
/* Slurp the whole file (minus the header) into a buffer. */
len = fread(buf, 1, sizeof(buf), fp);
fclose(fp);
/* 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))
+ if (len < 0 || len == sizeof(buf)) {
+ *error = "error reading file";
goto end; /* file too big or not read */
goto end; /* file too big or not read */
+ *error = "file format error";
/*
* A zero byte. (The signature includes a terminating NUL.)
/*
* A zero byte. (The signature includes a terminating NUL.)
if (key)
key->comment = comment;
if (!key) {
if (key)
key->comment = comment;
if (!key) {
- return ciphertype != 0;
+ ret = ciphertype != 0;
+ *error = NULL;
+ goto end;
if (len - i < 4)
goto end;
if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) {
if (len - i < 4)
goto end;
if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) {
+ *error = "wrong passphrase";
goto end;
if (!rsa_verify(key)) {
goto end;
if (!rsa_verify(key)) {
+ *error = "rsa_verify failed";
freersakey(key);
ret = 0;
} else
freersakey(key);
ret = 0;
} else
-int loadrsakey(const Filename *filename, struct RSAKey *key, char *passphrase)
+int loadrsakey(const Filename *filename, struct RSAKey *key, char *passphrase,
+ const char **errorstr)
{
FILE *fp;
char buf[64];
{
FILE *fp;
char buf[64];
+ int ret = 0;
+ const char *error = NULL;
fp = f_open(*filename, "rb");
fp = f_open(*filename, "rb");
- if (!fp)
- return 0; /* doesn't even exist */
+ if (!fp) {
+ error = "can't open file";
+ goto end;
+ }
/*
* 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)) {
/*
* 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, FALSE, NULL, passphrase);
+ ret = loadrsakey_main(fp, key, FALSE, NULL, passphrase, &error);
+ goto end;
}
/*
* Otherwise, we have nothing. Return empty-handed.
*/
fclose(fp);
}
/*
* Otherwise, we have nothing. Return empty-handed.
*/
fclose(fp);
+ error = "not an SSH-1 RSA file";
+
+ end:
+ if ((ret != 1) && errorstr)
+ *errorstr = error;
+ return ret;
* key file.
*/
if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
* key file.
*/
if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
- return loadrsakey_main(fp, NULL, FALSE, comment, NULL);
+ const char *dummy;
+ return loadrsakey_main(fp, NULL, FALSE, comment, NULL, &dummy);
}
fclose(fp);
return 0; /* wasn't the right kind of file */
}
fclose(fp);
return 0; /* wasn't the right kind of file */
* an RSA key, as given in the agent protocol (modulus bits,
* exponent, modulus).
*/
* an RSA key, as given in the agent protocol (modulus bits,
* exponent, modulus).
*/
-int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen)
+int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
+ const char **errorstr)
{
FILE *fp;
char buf[64];
struct RSAKey key;
int ret;
{
FILE *fp;
char buf[64];
struct RSAKey key;
int ret;
+ const char *error = NULL;
/* Default return if we fail. */
*blob = NULL;
/* Default return if we fail. */
*blob = NULL;
ret = 0;
fp = f_open(*filename, "rb");
ret = 0;
fp = f_open(*filename, "rb");
- if (!fp)
- return 0; /* doesn't even exist */
+ if (!fp) {
+ error = "can't open file";
+ goto end;
+ }
/*
* Read the first line of the file and see if it's a v1 private
/*
* Read the first line of the file and see if it's a v1 private
*/
if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
memset(&key, 0, sizeof(key));
*/
if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
memset(&key, 0, sizeof(key));
- if (loadrsakey_main(fp, &key, TRUE, NULL, NULL)) {
+ if (loadrsakey_main(fp, &key, TRUE, NULL, NULL, &error)) {
*blob = rsa_public_blob(&key, bloblen);
freersakey(&key);
ret = 1;
}
*blob = rsa_public_blob(&key, bloblen);
freersakey(&key);
ret = 1;
}
+ } else {
+ error = "not an SSH-1 RSA file";
+ fclose(fp);
+
+ end:
+ if ((ret != 1) && errorstr)
+ *errorstr = error;
};
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
};
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
+ char *passphrase, const char **errorstr)
{
FILE *fp;
char header[40], *b, *encryption, *comment, *mac;
{
FILE *fp;
char header[40], *b, *encryption, *comment, *mac;
int public_blob_len, private_blob_len;
int i, is_mac, old_fmt;
int passlen = passphrase ? strlen(passphrase) : 0;
int public_blob_len, private_blob_len;
int i, is_mac, old_fmt;
int passlen = passphrase ? strlen(passphrase) : 0;
+ const char *error = NULL;
ret = NULL; /* return NULL for most errors */
encryption = comment = mac = NULL;
public_blob = private_blob = NULL;
fp = f_open(*filename, "rb");
ret = NULL; /* return NULL for most errors */
encryption = comment = mac = NULL;
public_blob = private_blob = NULL;
fp = f_open(*filename, "rb");
+ if (!fp) {
+ error = "can't open file";
/* Read the first header line which contains the key type. */
if (!read_header(fp, header))
/* Read the first header line which contains the key type. */
if (!read_header(fp, header))
/* this is an old key file; warn and then continue */
old_keyfile_warning();
old_fmt = 1;
/* this is an old key file; warn and then continue */
old_keyfile_warning();
old_fmt = 1;
+ } else {
+ error = "not a PuTTY SSH-2 private key";
+ }
+ error = "file format error";
if ((b = read_body(fp)) == NULL)
goto error;
/* Select key algorithm structure. */
if ((b = read_body(fp)) == NULL)
goto error;
/* Select key algorithm structure. */
if (strcmp(mac, realmac)) {
/* An incorrect MAC is an unconditional Error if the key is
* unencrypted. Otherwise, it means Wrong Passphrase. */
if (strcmp(mac, realmac)) {
/* An incorrect MAC is an unconditional Error if the key is
* unencrypted. Otherwise, it means Wrong Passphrase. */
- ret = cipher ? SSH2_WRONG_PASSPHRASE : NULL;
+ if (cipher) {
+ ret = SSH2_WRONG_PASSPHRASE;
+ } else {
+ error = "MAC failed";
+ ret = NULL;
+ }
sfree(ret->comment);
sfree(ret);
ret = NULL;
sfree(ret->comment);
sfree(ret);
ret = NULL;
+ error = "createkey failed";
+ goto error;
}
sfree(public_blob);
sfree(private_blob);
sfree(encryption);
}
sfree(public_blob);
sfree(private_blob);
sfree(encryption);
sfree(public_blob);
if (private_blob)
sfree(private_blob);
sfree(public_blob);
if (private_blob)
sfree(private_blob);
+ if (errorstr)
+ *errorstr = error;
return ret;
}
char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
return ret;
}
char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
+ int *pub_blob_len, const char **errorstr)
{
FILE *fp;
char header[40], *b;
{
FILE *fp;
char header[40], *b;
unsigned char *public_blob;
int public_blob_len;
int i;
unsigned char *public_blob;
int public_blob_len;
int i;
+ const char *error = NULL;
public_blob = NULL;
fp = f_open(*filename, "rb");
public_blob = NULL;
fp = f_open(*filename, "rb");
+ if (!fp) {
+ error = "can't open file";
/* Read the first header line which contains the key type. */
if (!read_header(fp, header)
|| (0 != strcmp(header, "PuTTY-User-Key-File-2") &&
/* Read the first header line which contains the key type. */
if (!read_header(fp, header)
|| (0 != strcmp(header, "PuTTY-User-Key-File-2") &&
- 0 != strcmp(header, "PuTTY-User-Key-File-1")))
+ 0 != strcmp(header, "PuTTY-User-Key-File-1"))) {
+ error = "not a PuTTY SSH-2 private key";
+ }
+ error = "file format error";
if ((b = read_body(fp)) == NULL)
goto error;
/* Select key algorithm structure. Currently only ssh-rsa. */
if ((b = read_body(fp)) == NULL)
goto error;
/* Select key algorithm structure. Currently only ssh-rsa. */
fclose(fp);
if (public_blob)
sfree(public_blob);
fclose(fp);
if (public_blob)
sfree(public_blob);
+ if (errorstr)
+ *errorstr = error;