X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=cmdgen.c;h=adfe027f5e727136bc52d9c3239ec307f8dba3c0;hb=4d88fe3dde3448f3e940c424cf1de3221c3fde10;hp=3abc24527d3dbde49e99cd2843e0b41491800afb;hpb=da66c0656a6622a23cfdd8316e66681e487b87f1;p=PuTTY.git diff --git a/cmdgen.c b/cmdgen.c index 3abc2452..adfe027f 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -102,6 +102,16 @@ void modalfatalbox(char *p, ...) cleanup_exit(1); } +void nonfatal(char *p, ...) +{ + va_list ap; + fprintf(stderr, "ERROR: "); + va_start(ap, p); + vfprintf(stderr, p, ap); + va_end(ap); + fputc('\n', stderr); +} + /* * Stubs to let everything else link sensibly. */ @@ -118,10 +128,7 @@ void sk_cleanup(void) void showversion(void) { - char *verstr = dupstr(ver); - verstr[0] = tolower((unsigned char)verstr[0]); - printf("PuTTYgen %s\n", verstr); - sfree(verstr); + printf("puttygen: %s\n", ver); } void usage(int standalone) @@ -153,8 +160,10 @@ void help(void) " -O specify output type:\n" " private output PuTTY private key format\n" " private-openssh export OpenSSH private key\n" + " private-openssh-new export OpenSSH private key " + "(force new file format)\n" " private-sshcom export ssh.com private key\n" - " public standard / ssh.com public key\n" + " public RFC 4716 / ssh.com public key\n" " public-openssh OpenSSH public key\n" " fingerprint output the key fingerprint\n" " -o specify output file\n" @@ -257,11 +266,12 @@ static char *blobfp(char *alg, int bits, unsigned char *blob, int bloblen) int main(int argc, char **argv) { char *infile = NULL; - Filename *infilename, *outfilename; - enum { NOKEYGEN, RSA1, RSA2, DSA } keytype = NOKEYGEN; + Filename *infilename = NULL, *outfilename = NULL; + enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, ED25519 } keytype = NOKEYGEN; char *outfile = NULL, *outfiletmp = NULL; - enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH, SSHCOM } outtype = PRIVATE; - int bits = 1024; + enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_AUTO, + OPENSSH_NEW, SSHCOM } outtype = PRIVATE; + int bits = -1; char *comment = NULL, *origcomment = NULL; int change_passphrase = FALSE; int errs = FALSE, nogo = FALSE; @@ -430,6 +440,10 @@ int main(int argc, char **argv) keytype = RSA1, sshver = 1; else if (!strcmp(p, "dsa") || !strcmp(p, "dss")) keytype = DSA, sshver = 2; + else if (!strcmp(p, "ecdsa")) + keytype = ECDSA, sshver = 2; + else if (!strcmp(p, "ed25519")) + keytype = ED25519, sshver = 2; else { fprintf(stderr, "puttygen: unknown key type `%s'\n", p); @@ -452,7 +466,9 @@ int main(int argc, char **argv) else if (!strcmp(p, "fingerprint")) outtype = FP; else if (!strcmp(p, "private-openssh")) - outtype = OPENSSH, sshver = 2; + outtype = OPENSSH_AUTO, sshver = 2; + else if (!strcmp(p, "private-openssh-new")) + outtype = OPENSSH_NEW, sshver = 2; else if (!strcmp(p, "private-sshcom")) outtype = SSHCOM, sshver = 2; else { @@ -490,6 +506,34 @@ int main(int argc, char **argv) } } + if (bits == -1) { + /* + * No explicit key size was specified. Default varies + * depending on key type. + */ + switch (keytype) { + case ECDSA: + bits = 384; + break; + case ED25519: + bits = 256; + break; + default: + bits = 2048; + break; + } + } + + if (keytype == ECDSA && (bits != 256 && bits != 384 && bits != 521)) { + fprintf(stderr, "puttygen: invalid bits for ECDSA, choose 256, 384 or 521\n"); + errs = TRUE; + } + + if (keytype == ED25519 && (bits != 256)) { + fprintf(stderr, "puttygen: invalid bits for ED25519, choose 256\n"); + errs = TRUE; + } + if (errs) return 1; @@ -522,7 +566,8 @@ int main(int argc, char **argv) * We must save the private part when generating a new key. */ if (keytype != NOKEYGEN && - (outtype != PRIVATE && outtype != OPENSSH && outtype != SSHCOM)) { + (outtype != PRIVATE && outtype != OPENSSH_AUTO && + outtype != OPENSSH_NEW && outtype != SSHCOM)) { fprintf(stderr, "puttygen: this would generate a new key but " "discard the private part\n"); return 1; @@ -538,28 +583,6 @@ int main(int argc, char **argv) intype = key_type(infilename); switch (intype) { - /* - * It would be nice here to be able to load _public_ - * key files, in any of a number of forms, and (a) - * convert them to other public key types, (b) print - * out their fingerprints. Or, I suppose, for real - * orthogonality, (c) change their comment! - * - * In fact this opens some interesting possibilities. - * Suppose ssh2_userkey_loadpub() were able to load - * public key files as well as extracting the public - * key from private ones. And suppose I did the thing - * I've been wanting to do, where specifying a - * particular private key file for authentication - * causes any _other_ key in the agent to be discarded. - * Then, if you had an agent forwarded to the machine - * you were running Unix PuTTY or Plink on, and you - * needed to specify which of the keys in the agent it - * should use, you could do that by supplying a - * _public_ key file, thus not needing to trust even - * your encrypted private key file to the network. Ooh! - */ - case SSH_KEYTYPE_UNOPENABLE: case SSH_KEYTYPE_UNKNOWN: fprintf(stderr, "puttygen: unable to load file `%s': %s\n", @@ -567,6 +590,7 @@ int main(int argc, char **argv) return 1; case SSH_KEYTYPE_SSH1: + case SSH_KEYTYPE_SSH1_PUBLIC: if (sshver == 2) { fprintf(stderr, "puttygen: conversion from SSH-1 to SSH-2 keys" " not supported\n"); @@ -576,7 +600,10 @@ int main(int argc, char **argv) break; case SSH_KEYTYPE_SSH2: - case SSH_KEYTYPE_OPENSSH: + case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716: + case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH: + case SSH_KEYTYPE_OPENSSH_PEM: + case SSH_KEYTYPE_OPENSSH_NEW: case SSH_KEYTYPE_SSHCOM: if (sshver == 1) { fprintf(stderr, "puttygen: conversion from SSH-2 to SSH-1 keys" @@ -585,6 +612,10 @@ int main(int argc, char **argv) } sshver = 2; break; + + case SSH_KEYTYPE_OPENSSH_AUTO: + default: + assert(0 && "Should never see these types on an input file"); } } @@ -600,7 +631,8 @@ int main(int argc, char **argv) */ if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) || (intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) || - (intype == SSH_KEYTYPE_OPENSSH && outtype == OPENSSH) || + (intype == SSH_KEYTYPE_OPENSSH_PEM && outtype == OPENSSH_AUTO) || + (intype == SSH_KEYTYPE_OPENSSH_NEW && outtype == OPENSSH_NEW) || (intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) { if (!outfile) { outfile = infile; @@ -618,7 +650,8 @@ int main(int argc, char **argv) * Bomb out rather than automatically choosing to write * a private key file to stdout. */ - if (outtype==PRIVATE || outtype==OPENSSH || outtype==SSHCOM) { + if (outtype == PRIVATE || outtype == OPENSSH_AUTO || + outtype == OPENSSH_NEW || outtype == SSHCOM) { fprintf(stderr, "puttygen: need to specify an output file\n"); return 1; } @@ -631,12 +664,23 @@ int main(int argc, char **argv) * out a private key format, or (b) the entire input key file * is encrypted. */ - if (outtype == PRIVATE || outtype == OPENSSH || outtype == SSHCOM || - intype == SSH_KEYTYPE_OPENSSH || intype == SSH_KEYTYPE_SSHCOM) + if (outtype == PRIVATE || outtype == OPENSSH_AUTO || + outtype == OPENSSH_NEW || outtype == SSHCOM || + intype == SSH_KEYTYPE_OPENSSH_PEM || + intype == SSH_KEYTYPE_OPENSSH_NEW || + intype == SSH_KEYTYPE_SSHCOM) load_encrypted = TRUE; else load_encrypted = FALSE; + if (load_encrypted && (intype == SSH_KEYTYPE_SSH1_PUBLIC || + intype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || + intype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH)) { + fprintf(stderr, "puttygen: cannot perform this action on a " + "public-key-only input file\n"); + return 1; + } + /* ------------------------------------------------------------------ * Now we're ready to actually do some stuff. */ @@ -656,6 +700,10 @@ int main(int argc, char **argv) tm = ltime(); if (keytype == DSA) strftime(default_comment, 30, "dsa-key-%Y%m%d", &tm); + else if (keytype == ECDSA) + strftime(default_comment, 30, "ecdsa-key-%Y%m%d", &tm); + else if (keytype == ED25519) + strftime(default_comment, 30, "ed25519-key-%Y%m%d", &tm); else strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm); @@ -667,7 +715,7 @@ int main(int argc, char **argv) return 1; } random_add_heavynoise(entropy, bits / 8); - memset(entropy, 0, bits/8); + smemclr(entropy, bits/8); sfree(entropy); if (keytype == DSA) { @@ -677,6 +725,26 @@ int main(int argc, char **argv) ssh2key->data = dsskey; ssh2key->alg = &ssh_dss; ssh1key = NULL; + } else if (keytype == ECDSA) { + struct ec_key *ec = snew(struct ec_key); + 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; + } + ssh1key = NULL; + } else if (keytype == ED25519) { + struct ec_key *ec = snew(struct ec_key); + ec_edgenerate(ec, bits, progressfn, &prog); + ssh2key = snew(struct ssh2_userkey); + ssh2key->data = ec; + ssh2key->alg = &ssh_ecdsa_ed25519; + ssh1key = NULL; } else { struct RSAKey *rsakey = snew(struct RSAKey); rsa_generate(rsakey, bits, progressfn, &prog); @@ -739,6 +807,7 @@ int main(int argc, char **argv) int ret; case SSH_KEYTYPE_SSH1: + case SSH_KEYTYPE_SSH1_PUBLIC: ssh1key = snew(struct RSAKey); if (!load_encrypted) { void *vblob; @@ -766,6 +835,9 @@ int main(int argc, char **argv) } ssh1key->comment = dupstr(origcomment); ssh1key->private_exponent = NULL; + ssh1key->p = NULL; + ssh1key->q = NULL; + ssh1key->iqmp = NULL; } else { ret = loadrsakey(infilename, ssh1key, passphrase, &error); } @@ -776,14 +848,19 @@ int main(int argc, char **argv) break; case SSH_KEYTYPE_SSH2: + case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716: + case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH: if (!load_encrypted) { ssh2blob = ssh2_userkey_loadpub(infilename, &ssh2alg, - &ssh2bloblen, NULL, &error); - ssh2algf = find_pubkey_alg(ssh2alg); - if (ssh2algf) - bits = ssh2algf->pubkey_bits(ssh2blob, ssh2bloblen); - else - bits = -1; + &ssh2bloblen, &origcomment, + &error); + if (ssh2blob) { + ssh2algf = find_pubkey_alg(ssh2alg); + if (ssh2algf) + bits = ssh2algf->pubkey_bits(ssh2blob, ssh2bloblen); + else + bits = -1; + } } else { ssh2key = ssh2_load_userkey(infilename, passphrase, &error); } @@ -797,7 +874,8 @@ int main(int argc, char **argv) } break; - case SSH_KEYTYPE_OPENSSH: + case SSH_KEYTYPE_OPENSSH_PEM: + case SSH_KEYTYPE_OPENSSH_NEW: case SSH_KEYTYPE_SSHCOM: ssh2key = import_ssh2(infilename, intype, passphrase, &error); if (ssh2key) { @@ -860,7 +938,7 @@ int main(int argc, char **argv) return 1; } if (passphrase) { - memset(passphrase, 0, strlen(passphrase)); + smemclr(passphrase, strlen(passphrase)); sfree(passphrase); } passphrase = dupstr(p->prompts[0]->result); @@ -886,7 +964,7 @@ int main(int argc, char **argv) outfilename = filename_from_str(outfile ? outfile : ""); switch (outtype) { - int ret; + int ret, real_outtype; case PRIVATE: if (sshver == 1) { @@ -1018,11 +1096,27 @@ int main(int argc, char **argv) } break; - case OPENSSH: + case OPENSSH_AUTO: + case OPENSSH_NEW: case SSHCOM: assert(sshver == 2); assert(ssh2key); - ret = export_ssh2(outfilename, outtype, ssh2key, passphrase); + random_ref(); /* both foreign key types require randomness, + * for IV or padding */ + switch (outtype) { + case OPENSSH_AUTO: + real_outtype = SSH_KEYTYPE_OPENSSH_AUTO; + break; + case OPENSSH_NEW: + real_outtype = SSH_KEYTYPE_OPENSSH_NEW; + break; + case SSHCOM: + real_outtype = SSH_KEYTYPE_SSHCOM; + break; + default: + assert(0 && "control flow goof"); + } + ret = export_ssh2(outfilename, real_outtype, ssh2key, passphrase); if (!ret) { fprintf(stderr, "puttygen: unable to export key\n"); return 1; @@ -1035,7 +1129,7 @@ int main(int argc, char **argv) } if (passphrase) { - memset(passphrase, 0, strlen(passphrase)); + smemclr(passphrase, strlen(passphrase)); sfree(passphrase); }