#include <limits.h>
#include <assert.h>
#include <time.h>
+#include <errno.h>
+#include <string.h>
#include "putty.h"
#include "ssh.h"
" -l equivalent to `-O fingerprint'\n"
" -L equivalent to `-O public-openssh'\n"
" -p equivalent to `-O public'\n"
+ " --old-passphrase file\n"
+ " specify file containing old key passphrase\n"
+ " --new-passphrase file\n"
+ " specify file containing new key passphrase\n"
);
}
return TRUE;
}
+static char *readpassphrase(const char *filename)
+{
+ FILE *fp;
+ char *line;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "puttygen: cannot open %s: %s\n",
+ filename, strerror(errno));
+ return NULL;
+ }
+ line = fgetline(fp);
+ if (line)
+ line[strcspn(line, "\r\n")] = '\0';
+ else if (ferror(fp))
+ fprintf(stderr, "puttygen: error reading from %s: %s\n",
+ filename, strerror(errno));
+ else /* empty file */
+ line = dupstr("");
+ fclose(fp);
+ return line;
+}
+
int main(int argc, char **argv)
{
char *infile = NULL;
char *ssh2alg = NULL;
const struct ssh_signkey *ssh2algf = NULL;
int ssh2bloblen;
- char *passphrase = NULL;
+ char *old_passphrase = NULL, *new_passphrase = NULL;
int load_encrypted;
progfn_t progressfn = is_interactive() ? progress_update : no_progress;
pgp_fingerprints();
nogo = TRUE;
}
- }
- /*
- * For long options requiring an argument, add
- * code along the lines of
- *
- * else if (!strcmp(opt, "-output")) {
- * if (!val) {
- * errs = TRUE;
- * fprintf(stderr, "puttygen: option `-%s'"
- * " expects an argument\n", opt);
- * } else
- * ofile = val;
- * }
- */
- else {
+ } else if (!strcmp(opt, "-old-passphrase")) {
+ if (!val && argc > 1)
+ --argc, val = *++argv;
+ if (!val) {
+ errs = TRUE;
+ fprintf(stderr, "puttygen: option `-%s'"
+ " expects an argument\n", opt);
+ } else {
+ old_passphrase = readpassphrase(val);
+ if (!old_passphrase)
+ errs = TRUE;
+ }
+ } else if (!strcmp(opt, "-new-passphrase")) {
+ if (!val && argc > 1)
+ --argc, val = *++argv;
+ if (!val) {
+ errs = TRUE;
+ fprintf(stderr, "puttygen: option `-%s'"
+ " expects an argument\n", opt);
+ } else {
+ new_passphrase = readpassphrase(val);
+ if (!new_passphrase)
+ errs = TRUE;
+ }
+ } else {
errs = TRUE;
fprintf(stderr,
"puttygen: no such option `-%s'\n", opt);
* If so, ask for a passphrase.
*/
if (encrypted && load_encrypted) {
- prompts_t *p = new_prompts(NULL);
- int ret;
- p->to_server = FALSE;
- p->name = dupstr("SSH key passphrase");
- add_prompt(p, dupstr("Enter passphrase to load key: "), FALSE);
- ret = console_get_userpass_input(p, NULL, 0);
- assert(ret >= 0);
- if (!ret) {
- free_prompts(p);
- perror("puttygen: unable to read passphrase");
- return 1;
- } else {
- passphrase = dupstr(p->prompts[0]->result);
- free_prompts(p);
+ if (!old_passphrase) {
+ prompts_t *p = new_prompts(NULL);
+ int ret;
+ p->to_server = FALSE;
+ p->name = dupstr("SSH key passphrase");
+ add_prompt(p, dupstr("Enter passphrase to load key: "), FALSE);
+ ret = console_get_userpass_input(p, NULL, 0);
+ assert(ret >= 0);
+ if (!ret) {
+ free_prompts(p);
+ perror("puttygen: unable to read passphrase");
+ return 1;
+ } else {
+ old_passphrase = dupstr(p->prompts[0]->result);
+ free_prompts(p);
+ }
}
} else {
- passphrase = NULL;
+ old_passphrase = NULL;
}
switch (intype) {
ssh1key->q = NULL;
ssh1key->iqmp = NULL;
} else {
- ret = loadrsakey(infilename, ssh1key, passphrase, &error);
+ ret = loadrsakey(infilename, ssh1key, old_passphrase, &error);
}
if (ret > 0)
error = NULL;
}
sfree(ssh2alg);
} else {
- ssh2key = ssh2_load_userkey(infilename, passphrase, &error);
+ ssh2key = ssh2_load_userkey(infilename, old_passphrase,
+ &error);
}
if ((ssh2key && ssh2key != SSH2_WRONG_PASSPHRASE) || ssh2blob)
error = NULL;
case SSH_KEYTYPE_OPENSSH_PEM:
case SSH_KEYTYPE_OPENSSH_NEW:
case SSH_KEYTYPE_SSHCOM:
- ssh2key = import_ssh2(infilename, intype, passphrase, &error);
+ ssh2key = import_ssh2(infilename, intype, old_passphrase, &error);
if (ssh2key) {
if (ssh2key != SSH2_WRONG_PASSPHRASE)
error = NULL;
}
}
+ /*
+ * Unless we're changing the passphrase, the old one (if any) is a
+ * reasonable default.
+ */
+ if (!change_passphrase && old_passphrase && !new_passphrase)
+ new_passphrase = dupstr(old_passphrase);
+
/*
* Prompt for a new passphrase if we have been asked to, or if
* we have just generated a key.
*/
- if (change_passphrase || keytype != NOKEYGEN) {
+ if (!new_passphrase && (change_passphrase || keytype != NOKEYGEN)) {
prompts_t *p = new_prompts(NULL);
int ret;
fprintf(stderr, "puttygen: passphrases do not match\n");
return 1;
}
- if (passphrase) {
- smemclr(passphrase, strlen(passphrase));
- sfree(passphrase);
- }
- passphrase = dupstr(p->prompts[0]->result);
+ new_passphrase = dupstr(p->prompts[0]->result);
free_prompts(p);
- if (!*passphrase) {
- sfree(passphrase);
- passphrase = NULL;
- }
}
}
+ if (new_passphrase && !*new_passphrase) {
+ sfree(new_passphrase);
+ new_passphrase = NULL;
+ }
/*
* Write output.
case PRIVATE:
if (sshver == 1) {
assert(ssh1key);
- ret = saversakey(outfilename, ssh1key, passphrase);
+ ret = saversakey(outfilename, ssh1key, new_passphrase);
if (!ret) {
fprintf(stderr, "puttygen: unable to save SSH-1 private key\n");
return 1;
}
} else {
assert(ssh2key);
- ret = ssh2_save_userkey(outfilename, ssh2key, passphrase);
+ ret = ssh2_save_userkey(outfilename, ssh2key, new_passphrase);
if (!ret) {
fprintf(stderr, "puttygen: unable to save SSH-2 private key\n");
return 1;
default:
assert(0 && "control flow goof");
}
- ret = export_ssh2(outfilename, real_outtype, ssh2key, passphrase);
+ ret = export_ssh2(outfilename, real_outtype, ssh2key, new_passphrase);
if (!ret) {
fprintf(stderr, "puttygen: unable to export key\n");
return 1;
break;
}
- if (passphrase) {
- smemclr(passphrase, strlen(passphrase));
- sfree(passphrase);
+ if (old_passphrase) {
+ smemclr(old_passphrase, strlen(old_passphrase));
+ sfree(old_passphrase);
+ }
+ if (new_passphrase) {
+ smemclr(new_passphrase, strlen(new_passphrase));
+ sfree(new_passphrase);
}
if (ssh1key)