X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=cmdgen.c;h=d6c1f72115ac3080b17e7750aa1ee15350637e08;hb=1b2cc402448da230af90ade6331f4712f73df6b0;hp=c1f3a8cb96e03d29bd1a4c85351cf4981545c7bf;hpb=870ad6ab0780c68e0e71d1a14d394aa543a8b89e;p=PuTTY.git diff --git a/cmdgen.c b/cmdgen.c index c1f3a8cb..d6c1f721 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "putty.h" #include "ssh.h" @@ -17,7 +19,7 @@ #ifdef TEST_CMDGEN /* * This section overrides some definitions below for test purposes. - * When compiled with -DTEST_CMDGEN: + * When compiled with -DTEST_CMDGEN (as cgtest.c will do): * * - Calls to get_random_data() are replaced with the diagnostic * function below (I #define the name so that I can still link @@ -35,7 +37,7 @@ * run tests. */ #define get_random_data get_random_data_diagnostic -char *get_random_data(int len) +char *get_random_data(int len, const char *device) { char *buf = snewn(len, char); memset(buf, 'x', len); @@ -50,8 +52,7 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen) int ret = 1; for (i = 0; i < p->n_prompts; i++) { if (promptsgot < nprompts) { - assert(strlen(prompts[promptsgot]) < p->prompts[i]->result_len); - strcpy(p->prompts[i]->result, prompts[promptsgot++]); + p->prompts[i]->result = dupstr(prompts[promptsgot++]); } else { promptsgot++; /* track number of requests anyway */ ret = 0; @@ -91,7 +92,7 @@ static void no_progress(void *param, int action, int phase, int iprogress) { } -void modalfatalbox(char *p, ...) +void modalfatalbox(const char *p, ...) { va_list ap; fprintf(stderr, "FATAL ERROR: "); @@ -102,7 +103,7 @@ void modalfatalbox(char *p, ...) cleanup_exit(1); } -void nonfatal(char *p, ...) +void nonfatal(const char *p, ...) { va_list ap; fprintf(stderr, "ERROR: "); @@ -128,7 +129,9 @@ void sk_cleanup(void) void showversion(void) { - printf("puttygen: %s\n", ver); + char *buildinfo_text = buildinfo("\n"); + printf("puttygen: %s\n%s", ver, buildinfo_text); + sfree(buildinfo_text); } void usage(int standalone) @@ -152,7 +155,8 @@ void help(void) showversion(); usage(FALSE); fprintf(stderr, - " -t specify key type when generating (rsa, dsa, rsa1)\n" + " -t specify key type when generating (ed25519, ecdsa, rsa, " + "dsa, rsa1)\n" " -b specify number of bits when generating key\n" " -C change or specify key comment\n" " -P change key passphrase\n" @@ -170,6 +174,12 @@ void help(void) " -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" + " --random-device device\n" + " specify device to read entropy from (e.g. /dev/urandom)\n" ); } @@ -192,6 +202,31 @@ static int move(char *from, char *to) 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; +} + +#define DEFAULT_RSADSA_BITS 2048 + int main(int argc, char **argv) { char *infile = NULL; @@ -212,9 +247,10 @@ int main(int argc, char **argv) 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; + const char *random_device = NULL; /* ------------------------------------------------------------------ * Parse the command line to figure out what we've been asked to do. @@ -284,21 +320,41 @@ int main(int argc, char **argv) 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 if (!strcmp(opt, "-random-device")) { + if (!val && argc > 1) + --argc, val = *++argv; + if (!val) { + errs = TRUE; + fprintf(stderr, "puttygen: option `-%s'" + " expects an argument\n", opt); + } else { + random_device = val; + } + } else { errs = TRUE; fprintf(stderr, "puttygen: no such option `-%s'\n", opt); @@ -448,7 +504,7 @@ int main(int argc, char **argv) bits = 256; break; default: - bits = 2048; + bits = DEFAULT_RSADSA_BITS; break; } } @@ -463,6 +519,19 @@ int main(int argc, char **argv) errs = TRUE; } + if (keytype == RSA2 || keytype == RSA1 || keytype == DSA) { + if (bits < 256) { + fprintf(stderr, "puttygen: cannot generate %s keys shorter than" + " 256 bits\n", (keytype == DSA ? "DSA" : "RSA")); + errs = TRUE; + } else if (bits < DEFAULT_RSADSA_BITS) { + fprintf(stderr, "puttygen: warning: %s keys shorter than" + " %d bits are probably not secure\n", + (keytype == DSA ? "DSA" : "RSA"), DEFAULT_RSADSA_BITS); + /* but this is just a warning, so proceed anyway */ + } + } + if (errs) return 1; @@ -637,7 +706,7 @@ int main(int argc, char **argv) strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm); random_ref(); - entropy = get_random_data(bits / 8); + entropy = get_random_data(bits / 8, random_device); if (!entropy) { fprintf(stderr, "puttygen: failed to collect entropy, " "could not generate key\n"); @@ -659,13 +728,7 @@ int main(int argc, char **argv) ec_generate(ec, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); ssh2key->data = ec; - if (bits == 256) { - ssh2key->alg = &ssh_ecdsa_nistp256; - } else if (bits == 384) { - ssh2key->alg = &ssh_ecdsa_nistp384; - } else { - ssh2key->alg = &ssh_ecdsa_nistp521; - } + ssh2key->alg = ec->signalg; ssh1key = NULL; } else if (keytype == ED25519) { struct ec_key *ec = snew(struct ec_key); @@ -713,23 +776,25 @@ int main(int argc, char **argv) * 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) { @@ -768,7 +833,7 @@ int main(int argc, char **argv) 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; @@ -793,7 +858,8 @@ int main(int argc, char **argv) } 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; @@ -808,7 +874,7 @@ int main(int argc, char **argv) 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; @@ -844,11 +910,18 @@ int main(int argc, char **argv) } } + /* + * 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; @@ -868,18 +941,14 @@ int main(int argc, char **argv) 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. @@ -900,14 +969,14 @@ int main(int argc, char **argv) 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; @@ -1001,7 +1070,7 @@ int main(int argc, char **argv) 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; @@ -1013,9 +1082,13 @@ int main(int argc, char **argv) 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) @@ -1136,7 +1209,7 @@ char *cleanup_fp(char *s) s += strspn(s, " \n\t"); s += strcspn(s, " \n\t"); - return dupprintf("%.*s", s - p, p); + return dupprintf("%.*s", (int)(s - p), p); } char *get_fp(char *filename)