Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.113.2.1
1.1 deraadt 1: /*
1.13 deraadt 2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
5: * Identity and host key generation and maintenance.
1.31 deraadt 6: *
7: * As far as I am concerned, the code I have written for this software
8: * can be used freely for any purpose. Any derived versions of this
9: * software must be clearly marked as such, and if the derived work is
10: * incompatible with the protocol description in the RFC file, it must be
11: * called by a name other than "ssh" or "Secure Shell".
1.13 deraadt 12: */
1.1 deraadt 13:
14: #include "includes.h"
1.113.2.1! brad 15: RCSID("$OpenBSD: ssh-keygen.c,v 1.117 2004/07/11 17:48:47 deraadt Exp $");
1.19 markus 16:
17: #include <openssl/evp.h>
18: #include <openssl/pem.h>
1.1 deraadt 19:
20: #include "xmalloc.h"
1.19 markus 21: #include "key.h"
1.53 markus 22: #include "rsa.h"
1.19 markus 23: #include "authfile.h"
24: #include "uuencode.h"
1.32 markus 25: #include "buffer.h"
26: #include "bufaux.h"
1.40 markus 27: #include "pathnames.h"
1.41 markus 28: #include "log.h"
1.113.2.1! brad 29: #include "misc.h"
1.32 markus 30:
1.75 markus 31: #ifdef SMARTCARD
32: #include "scard.h"
1.106 djm 33: #endif
34: #include "dns.h"
1.66 markus 35:
1.19 markus 36: /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
1.1 deraadt 37: int bits = 1024;
38:
1.14 markus 39: /*
40: * Flag indicating that we just want to change the passphrase. This can be
41: * set on the command line.
42: */
1.1 deraadt 43: int change_passphrase = 0;
44:
1.14 markus 45: /*
46: * Flag indicating that we just want to change the comment. This can be set
47: * on the command line.
48: */
1.1 deraadt 49: int change_comment = 0;
50:
1.2 provos 51: int quiet = 0;
52:
1.8 markus 53: /* Flag indicating that we just want to see the key fingerprint */
54: int print_fingerprint = 0;
1.49 markus 55: int print_bubblebabble = 0;
1.8 markus 56:
1.10 markus 57: /* The identity file name, given on the command line or entered by the user. */
58: char identity_file[1024];
59: int have_identity = 0;
1.1 deraadt 60:
61: /* This is set to the passphrase if given on the command line. */
62: char *identity_passphrase = NULL;
63:
64: /* This is set to the new passphrase if given on the command line. */
65: char *identity_new_passphrase = NULL;
66:
67: /* This is set to the new comment if given on the command line. */
68: char *identity_comment = NULL;
69:
1.19 markus 70: /* Dump public key file in format used by real and the original SSH 2 */
71: int convert_to_ssh2 = 0;
72: int convert_from_ssh2 = 0;
73: int print_public = 0;
1.105 jakob 74: int print_generic = 0;
1.33 markus 75:
1.87 djm 76: char *key_type_name = NULL;
1.19 markus 77:
1.10 markus 78: /* argv0 */
79: extern char *__progname;
1.1 deraadt 80:
1.19 markus 81: char hostname[MAXHOSTNAMELEN];
82:
1.113.2.1! brad 83: /* moduli.c */
! 84: int gen_candidates(FILE *, int, int, BIGNUM *);
! 85: int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
! 86:
1.63 itojun 87: static void
1.10 markus 88: ask_filename(struct passwd *pw, const char *prompt)
1.1 deraadt 89: {
1.12 markus 90: char buf[1024];
1.35 markus 91: char *name = NULL;
92:
1.92 stevesk 93: if (key_type_name == NULL)
1.40 markus 94: name = _PATH_SSH_CLIENT_ID_RSA;
1.92 stevesk 95: else
96: switch (key_type_from_name(key_type_name)) {
97: case KEY_RSA1:
98: name = _PATH_SSH_CLIENT_IDENTITY;
99: break;
100: case KEY_DSA:
101: name = _PATH_SSH_CLIENT_ID_DSA;
102: break;
103: case KEY_RSA:
104: name = _PATH_SSH_CLIENT_ID_RSA;
105: break;
106: default:
107: fprintf(stderr, "bad key type");
108: exit(1);
109: break;
110: }
111:
1.35 markus 112: snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
1.37 markus 113: fprintf(stderr, "%s (%s): ", prompt, identity_file);
1.12 markus 114: if (fgets(buf, sizeof(buf), stdin) == NULL)
115: exit(1);
116: if (strchr(buf, '\n'))
117: *strchr(buf, '\n') = 0;
118: if (strcmp(buf, "") != 0)
119: strlcpy(identity_file, buf, sizeof(identity_file));
120: have_identity = 1;
1.7 markus 121: }
122:
1.63 itojun 123: static Key *
1.61 markus 124: load_identity(char *filename)
1.19 markus 125: {
1.52 markus 126: char *pass;
127: Key *prv;
128:
1.55 markus 129: prv = key_load_private(filename, "", NULL);
1.52 markus 130: if (prv == NULL) {
1.61 markus 131: if (identity_passphrase)
132: pass = xstrdup(identity_passphrase);
133: else
1.65 markus 134: pass = read_passphrase("Enter passphrase: ",
135: RP_ALLOW_STDIN);
1.52 markus 136: prv = key_load_private(filename, pass, NULL);
1.19 markus 137: memset(pass, 0, strlen(pass));
138: xfree(pass);
139: }
1.52 markus 140: return prv;
1.19 markus 141: }
142:
1.32 markus 143: #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
1.100 deraadt 144: #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
1.32 markus 145: #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
1.42 stevesk 146: #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
1.19 markus 147:
1.63 itojun 148: static void
1.19 markus 149: do_convert_to_ssh2(struct passwd *pw)
150: {
1.59 markus 151: Key *k;
1.94 markus 152: u_int len;
1.36 markus 153: u_char *blob;
1.19 markus 154: struct stat st;
155:
156: if (!have_identity)
157: ask_filename(pw, "Enter file in which the key is");
158: if (stat(identity_file, &st) < 0) {
159: perror(identity_file);
160: exit(1);
161: }
1.59 markus 162: if ((k = key_load_public(identity_file, NULL)) == NULL) {
1.61 markus 163: if ((k = load_identity(identity_file)) == NULL) {
1.59 markus 164: fprintf(stderr, "load failed\n");
165: exit(1);
166: }
1.104 markus 167: }
168: if (k->type == KEY_RSA1) {
169: fprintf(stderr, "version 1 keys are not supported\n");
170: exit(1);
1.19 markus 171: }
1.81 markus 172: if (key_to_blob(k, &blob, &len) <= 0) {
173: fprintf(stderr, "key_to_blob failed\n");
174: exit(1);
175: }
1.32 markus 176: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
1.19 markus 177: fprintf(stdout,
1.101 deraadt 178: "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
1.59 markus 179: key_size(k), key_type(k),
1.19 markus 180: pw->pw_name, hostname);
181: dump_base64(stdout, blob, len);
1.32 markus 182: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
1.59 markus 183: key_free(k);
1.21 markus 184: xfree(blob);
1.19 markus 185: exit(0);
186: }
187:
1.63 itojun 188: static void
1.32 markus 189: buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
190: {
1.113.2.1! brad 191: u_int bignum_bits = buffer_get_int(b);
! 192: u_int bytes = (bignum_bits + 7) / 8;
1.53 markus 193:
1.32 markus 194: if (buffer_len(b) < bytes)
1.53 markus 195: fatal("buffer_get_bignum_bits: input buffer too small: "
196: "need %d have %d", bytes, buffer_len(b));
1.89 stevesk 197: BN_bin2bn(buffer_ptr(b), bytes, value);
1.32 markus 198: buffer_consume(b, bytes);
199: }
200:
1.63 itojun 201: static Key *
1.93 markus 202: do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
1.32 markus 203: {
204: Buffer b;
205: Key *key = NULL;
1.64 markus 206: char *type, *cipher;
1.69 stevesk 207: u_char *sig, data[] = "abcde12345";
1.62 markus 208: int magic, rlen, ktype, i1, i2, i3, i4;
1.64 markus 209: u_int slen;
1.62 markus 210: u_long e;
1.32 markus 211:
212: buffer_init(&b);
213: buffer_append(&b, blob, blen);
214:
215: magic = buffer_get_int(&b);
216: if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
217: error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
218: buffer_free(&b);
219: return NULL;
220: }
1.62 markus 221: i1 = buffer_get_int(&b);
1.32 markus 222: type = buffer_get_string(&b, NULL);
223: cipher = buffer_get_string(&b, NULL);
1.62 markus 224: i2 = buffer_get_int(&b);
225: i3 = buffer_get_int(&b);
226: i4 = buffer_get_int(&b);
227: debug("ignore (%d %d %d %d)", i1,i2,i3,i4);
1.32 markus 228: if (strcmp(cipher, "none") != 0) {
229: error("unsupported cipher %s", cipher);
230: xfree(cipher);
231: buffer_free(&b);
1.53 markus 232: xfree(type);
1.32 markus 233: return NULL;
234: }
235: xfree(cipher);
236:
1.53 markus 237: if (strstr(type, "dsa")) {
238: ktype = KEY_DSA;
239: } else if (strstr(type, "rsa")) {
240: ktype = KEY_RSA;
241: } else {
242: xfree(type);
1.32 markus 243: return NULL;
244: }
1.53 markus 245: key = key_new_private(ktype);
246: xfree(type);
247:
248: switch (key->type) {
249: case KEY_DSA:
250: buffer_get_bignum_bits(&b, key->dsa->p);
251: buffer_get_bignum_bits(&b, key->dsa->g);
252: buffer_get_bignum_bits(&b, key->dsa->q);
253: buffer_get_bignum_bits(&b, key->dsa->pub_key);
254: buffer_get_bignum_bits(&b, key->dsa->priv_key);
255: break;
256: case KEY_RSA:
1.62 markus 257: e = buffer_get_char(&b);
258: debug("e %lx", e);
259: if (e < 30) {
260: e <<= 8;
261: e += buffer_get_char(&b);
262: debug("e %lx", e);
263: e <<= 8;
264: e += buffer_get_char(&b);
265: debug("e %lx", e);
266: }
267: if (!BN_set_word(key->rsa->e, e)) {
1.53 markus 268: buffer_free(&b);
269: key_free(key);
270: return NULL;
271: }
272: buffer_get_bignum_bits(&b, key->rsa->d);
273: buffer_get_bignum_bits(&b, key->rsa->n);
274: buffer_get_bignum_bits(&b, key->rsa->iqmp);
275: buffer_get_bignum_bits(&b, key->rsa->q);
276: buffer_get_bignum_bits(&b, key->rsa->p);
1.68 markus 277: rsa_generate_additional_parameters(key->rsa);
1.53 markus 278: break;
279: }
1.32 markus 280: rlen = buffer_len(&b);
1.85 deraadt 281: if (rlen != 0)
1.53 markus 282: error("do_convert_private_ssh2_from_blob: "
283: "remaining bytes in key blob %d", rlen);
1.32 markus 284: buffer_free(&b);
1.64 markus 285:
286: /* try the key */
287: key_sign(key, &sig, &slen, data, sizeof(data));
288: key_verify(key, sig, slen, data, sizeof(data));
289: xfree(sig);
1.32 markus 290: return key;
291: }
292:
1.63 itojun 293: static void
1.19 markus 294: do_convert_from_ssh2(struct passwd *pw)
295: {
296: Key *k;
297: int blen;
1.98 markus 298: u_int len;
1.19 markus 299: char line[1024], *p;
1.80 stevesk 300: u_char blob[8096];
1.19 markus 301: char encoded[8096];
302: struct stat st;
1.32 markus 303: int escaped = 0, private = 0, ok;
1.19 markus 304: FILE *fp;
305:
306: if (!have_identity)
307: ask_filename(pw, "Enter file in which the key is");
308: if (stat(identity_file, &st) < 0) {
309: perror(identity_file);
310: exit(1);
311: }
312: fp = fopen(identity_file, "r");
313: if (fp == NULL) {
314: perror(identity_file);
315: exit(1);
316: }
317: encoded[0] = '\0';
318: while (fgets(line, sizeof(line), fp)) {
1.25 markus 319: if (!(p = strchr(line, '\n'))) {
320: fprintf(stderr, "input line too long.\n");
321: exit(1);
322: }
323: if (p > line && p[-1] == '\\')
324: escaped++;
1.19 markus 325: if (strncmp(line, "----", 4) == 0 ||
326: strstr(line, ": ") != NULL) {
1.32 markus 327: if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
328: private = 1;
1.64 markus 329: if (strstr(line, " END ") != NULL) {
330: break;
331: }
1.60 markus 332: /* fprintf(stderr, "ignore: %s", line); */
1.19 markus 333: continue;
334: }
1.25 markus 335: if (escaped) {
336: escaped--;
1.60 markus 337: /* fprintf(stderr, "escaped: %s", line); */
1.25 markus 338: continue;
1.19 markus 339: }
340: *p = '\0';
341: strlcat(encoded, line, sizeof(encoded));
342: }
1.98 markus 343: len = strlen(encoded);
344: if (((len % 4) == 3) &&
345: (encoded[len-1] == '=') &&
346: (encoded[len-2] == '=') &&
347: (encoded[len-3] == '='))
348: encoded[len-3] = '\0';
1.91 stevesk 349: blen = uudecode(encoded, blob, sizeof(blob));
1.19 markus 350: if (blen < 0) {
351: fprintf(stderr, "uudecode failed.\n");
352: exit(1);
353: }
1.32 markus 354: k = private ?
355: do_convert_private_ssh2_from_blob(blob, blen) :
1.33 markus 356: key_from_blob(blob, blen);
1.32 markus 357: if (k == NULL) {
358: fprintf(stderr, "decode blob failed.\n");
359: exit(1);
360: }
361: ok = private ?
1.53 markus 362: (k->type == KEY_DSA ?
363: PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
364: PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
1.32 markus 365: key_write(k, stdout);
366: if (!ok) {
367: fprintf(stderr, "key write failed");
368: exit(1);
369: }
1.19 markus 370: key_free(k);
1.90 markus 371: if (!private)
372: fprintf(stdout, "\n");
1.19 markus 373: fclose(fp);
374: exit(0);
375: }
376:
1.63 itojun 377: static void
1.19 markus 378: do_print_public(struct passwd *pw)
379: {
1.52 markus 380: Key *prv;
1.19 markus 381: struct stat st;
382:
383: if (!have_identity)
384: ask_filename(pw, "Enter file in which the key is");
385: if (stat(identity_file, &st) < 0) {
386: perror(identity_file);
387: exit(1);
388: }
1.61 markus 389: prv = load_identity(identity_file);
1.52 markus 390: if (prv == NULL) {
1.19 markus 391: fprintf(stderr, "load failed\n");
392: exit(1);
393: }
1.52 markus 394: if (!key_write(prv, stdout))
1.19 markus 395: fprintf(stderr, "key_write failed");
1.52 markus 396: key_free(prv);
1.19 markus 397: fprintf(stdout, "\n");
398: exit(0);
399: }
400:
1.74 markus 401: #ifdef SMARTCARD
1.66 markus 402: static void
1.75 markus 403: do_upload(struct passwd *pw, const char *sc_reader_id)
1.66 markus 404: {
405: Key *prv = NULL;
406: struct stat st;
1.95 markus 407: int ret;
1.66 markus 408:
409: if (!have_identity)
410: ask_filename(pw, "Enter file in which the key is");
411: if (stat(identity_file, &st) < 0) {
412: perror(identity_file);
1.95 markus 413: exit(1);
1.66 markus 414: }
415: prv = load_identity(identity_file);
416: if (prv == NULL) {
417: error("load failed");
1.95 markus 418: exit(1);
1.66 markus 419: }
1.95 markus 420: ret = sc_put_key(prv, sc_reader_id);
421: key_free(prv);
422: if (ret < 0)
423: exit(1);
1.103 itojun 424: logit("loading key done");
1.95 markus 425: exit(0);
1.74 markus 426: }
1.75 markus 427:
428: static void
429: do_download(struct passwd *pw, const char *sc_reader_id)
430: {
1.97 markus 431: Key **keys = NULL;
432: int i;
1.75 markus 433:
1.97 markus 434: keys = sc_get_keys(sc_reader_id, NULL);
435: if (keys == NULL)
1.75 markus 436: fatal("cannot read public key from smartcard");
1.97 markus 437: for (i = 0; keys[i]; i++) {
438: key_write(keys[i], stdout);
439: key_free(keys[i]);
440: fprintf(stdout, "\n");
441: }
442: xfree(keys);
1.75 markus 443: exit(0);
444: }
1.78 jakob 445: #endif /* SMARTCARD */
1.66 markus 446:
1.63 itojun 447: static void
1.8 markus 448: do_fingerprint(struct passwd *pw)
449: {
1.15 markus 450: FILE *f;
1.19 markus 451: Key *public;
1.49 markus 452: char *comment = NULL, *cp, *ep, line[16*1024], *fp;
1.84 stevesk 453: int i, skip = 0, num = 1, invalid = 1;
454: enum fp_rep rep;
455: enum fp_type fptype;
1.12 markus 456: struct stat st;
457:
1.52 markus 458: fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
459: rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
1.49 markus 460:
1.12 markus 461: if (!have_identity)
462: ask_filename(pw, "Enter file in which the key is");
463: if (stat(identity_file, &st) < 0) {
464: perror(identity_file);
465: exit(1);
466: }
1.52 markus 467: public = key_load_public(identity_file, &comment);
468: if (public != NULL) {
469: fp = key_fingerprint(public, fptype, rep);
1.101 deraadt 470: printf("%u %s %s\n", key_size(public), fp, comment);
1.33 markus 471: key_free(public);
472: xfree(comment);
1.49 markus 473: xfree(fp);
1.15 markus 474: exit(0);
475: }
1.52 markus 476: if (comment)
477: xfree(comment);
1.15 markus 478:
479: f = fopen(identity_file, "r");
480: if (f != NULL) {
481: while (fgets(line, sizeof(line), f)) {
482: i = strlen(line) - 1;
483: if (line[i] != '\n') {
484: error("line %d too long: %.40s...", num, line);
485: skip = 1;
486: continue;
487: }
488: num++;
489: if (skip) {
490: skip = 0;
491: continue;
492: }
493: line[i] = '\0';
494:
495: /* Skip leading whitespace, empty and comment lines. */
496: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
497: ;
498: if (!*cp || *cp == '\n' || *cp == '#')
499: continue ;
500: i = strtol(cp, &ep, 10);
501: if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
502: int quoted = 0;
503: comment = cp;
1.101 deraadt 504: for (; *cp && (quoted || (*cp != ' ' &&
505: *cp != '\t')); cp++) {
1.15 markus 506: if (*cp == '\\' && cp[1] == '"')
507: cp++; /* Skip both */
508: else if (*cp == '"')
509: quoted = !quoted;
510: }
511: if (!*cp)
512: continue;
513: *cp++ = '\0';
514: }
515: ep = cp;
1.38 markus 516: public = key_new(KEY_RSA1);
517: if (key_read(public, &cp) != 1) {
518: cp = ep;
519: key_free(public);
520: public = key_new(KEY_UNSPEC);
521: if (key_read(public, &cp) != 1) {
522: key_free(public);
523: continue;
524: }
1.12 markus 525: }
1.38 markus 526: comment = *cp ? cp : comment;
1.52 markus 527: fp = key_fingerprint(public, fptype, rep);
1.101 deraadt 528: printf("%u %s %s\n", key_size(public), fp,
1.38 markus 529: comment ? comment : "no comment");
1.49 markus 530: xfree(fp);
1.52 markus 531: key_free(public);
1.38 markus 532: invalid = 0;
1.12 markus 533: }
1.15 markus 534: fclose(f);
535: }
536: if (invalid) {
1.83 markus 537: printf("%s is not a public key file.\n", identity_file);
1.15 markus 538: exit(1);
1.12 markus 539: }
540: exit(0);
1.8 markus 541: }
542:
1.13 deraadt 543: /*
544: * Perform changing a passphrase. The argument is the passwd structure
545: * for the current user.
546: */
1.63 itojun 547: static void
1.7 markus 548: do_change_passphrase(struct passwd *pw)
549: {
1.12 markus 550: char *comment;
551: char *old_passphrase, *passphrase1, *passphrase2;
552: struct stat st;
1.19 markus 553: Key *private;
1.12 markus 554:
555: if (!have_identity)
556: ask_filename(pw, "Enter file in which the key is");
557: if (stat(identity_file, &st) < 0) {
558: perror(identity_file);
559: exit(1);
560: }
561: /* Try to load the file with empty passphrase. */
1.52 markus 562: private = key_load_private(identity_file, "", &comment);
563: if (private == NULL) {
1.12 markus 564: if (identity_passphrase)
565: old_passphrase = xstrdup(identity_passphrase);
566: else
1.65 markus 567: old_passphrase =
568: read_passphrase("Enter old passphrase: ",
569: RP_ALLOW_STDIN);
570: private = key_load_private(identity_file, old_passphrase,
571: &comment);
1.52 markus 572: memset(old_passphrase, 0, strlen(old_passphrase));
573: xfree(old_passphrase);
574: if (private == NULL) {
1.12 markus 575: printf("Bad passphrase.\n");
576: exit(1);
577: }
578: }
579: printf("Key has comment '%s'\n", comment);
580:
581: /* Ask the new passphrase (twice). */
582: if (identity_new_passphrase) {
583: passphrase1 = xstrdup(identity_new_passphrase);
584: passphrase2 = NULL;
585: } else {
586: passphrase1 =
1.65 markus 587: read_passphrase("Enter new passphrase (empty for no "
588: "passphrase): ", RP_ALLOW_STDIN);
589: passphrase2 = read_passphrase("Enter same passphrase again: ",
1.86 deraadt 590: RP_ALLOW_STDIN);
1.12 markus 591:
592: /* Verify that they are the same. */
593: if (strcmp(passphrase1, passphrase2) != 0) {
594: memset(passphrase1, 0, strlen(passphrase1));
595: memset(passphrase2, 0, strlen(passphrase2));
596: xfree(passphrase1);
597: xfree(passphrase2);
598: printf("Pass phrases do not match. Try again.\n");
599: exit(1);
600: }
601: /* Destroy the other copy. */
602: memset(passphrase2, 0, strlen(passphrase2));
603: xfree(passphrase2);
604: }
605:
606: /* Save the file using the new passphrase. */
1.52 markus 607: if (!key_save_private(private, identity_file, passphrase1, comment)) {
1.56 markus 608: printf("Saving the key failed: %s.\n", identity_file);
1.12 markus 609: memset(passphrase1, 0, strlen(passphrase1));
610: xfree(passphrase1);
1.19 markus 611: key_free(private);
1.12 markus 612: xfree(comment);
613: exit(1);
614: }
615: /* Destroy the passphrase and the copy of the key in memory. */
616: memset(passphrase1, 0, strlen(passphrase1));
617: xfree(passphrase1);
1.19 markus 618: key_free(private); /* Destroys contents */
1.12 markus 619: xfree(comment);
1.1 deraadt 620:
1.12 markus 621: printf("Your identification has been saved with the new passphrase.\n");
622: exit(0);
1.1 deraadt 623: }
624:
1.105 jakob 625: /*
626: * Print the SSHFP RR.
627: */
628: static void
1.113.2.1! brad 629: do_print_resource_record(struct passwd *pw, char *hname)
1.105 jakob 630: {
631: Key *public;
632: char *comment = NULL;
633: struct stat st;
634:
635: if (!have_identity)
636: ask_filename(pw, "Enter file in which the key is");
637: if (stat(identity_file, &st) < 0) {
638: perror(identity_file);
639: exit(1);
640: }
641: public = key_load_public(identity_file, &comment);
642: if (public != NULL) {
1.113.2.1! brad 643: export_dns_rr(hname, public, stdout, print_generic);
1.105 jakob 644: key_free(public);
645: xfree(comment);
646: exit(0);
647: }
648: if (comment)
649: xfree(comment);
650:
651: printf("failed to read v2 public key from %s.\n", identity_file);
652: exit(1);
653: }
654:
1.13 deraadt 655: /*
656: * Change the comment of a private key file.
657: */
1.63 itojun 658: static void
1.2 provos 659: do_change_comment(struct passwd *pw)
1.1 deraadt 660: {
1.46 deraadt 661: char new_comment[1024], *comment, *passphrase;
1.52 markus 662: Key *private;
663: Key *public;
1.12 markus 664: struct stat st;
665: FILE *f;
1.46 deraadt 666: int fd;
1.12 markus 667:
668: if (!have_identity)
669: ask_filename(pw, "Enter file in which the key is");
670: if (stat(identity_file, &st) < 0) {
671: perror(identity_file);
672: exit(1);
673: }
1.52 markus 674: private = key_load_private(identity_file, "", &comment);
675: if (private == NULL) {
1.12 markus 676: if (identity_passphrase)
677: passphrase = xstrdup(identity_passphrase);
678: else if (identity_new_passphrase)
679: passphrase = xstrdup(identity_new_passphrase);
680: else
1.65 markus 681: passphrase = read_passphrase("Enter passphrase: ",
682: RP_ALLOW_STDIN);
1.12 markus 683: /* Try to load using the passphrase. */
1.52 markus 684: private = key_load_private(identity_file, passphrase, &comment);
685: if (private == NULL) {
1.12 markus 686: memset(passphrase, 0, strlen(passphrase));
687: xfree(passphrase);
688: printf("Bad passphrase.\n");
689: exit(1);
690: }
1.52 markus 691: } else {
692: passphrase = xstrdup("");
1.12 markus 693: }
1.52 markus 694: if (private->type != KEY_RSA1) {
695: fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
696: key_free(private);
697: exit(1);
1.86 deraadt 698: }
1.12 markus 699: printf("Key now has comment '%s'\n", comment);
700:
701: if (identity_comment) {
702: strlcpy(new_comment, identity_comment, sizeof(new_comment));
703: } else {
704: printf("Enter new comment: ");
705: fflush(stdout);
706: if (!fgets(new_comment, sizeof(new_comment), stdin)) {
707: memset(passphrase, 0, strlen(passphrase));
1.19 markus 708: key_free(private);
1.12 markus 709: exit(1);
710: }
711: if (strchr(new_comment, '\n'))
712: *strchr(new_comment, '\n') = 0;
713: }
714:
715: /* Save the file using the new passphrase. */
1.52 markus 716: if (!key_save_private(private, identity_file, passphrase, new_comment)) {
1.56 markus 717: printf("Saving the key failed: %s.\n", identity_file);
1.12 markus 718: memset(passphrase, 0, strlen(passphrase));
719: xfree(passphrase);
1.19 markus 720: key_free(private);
1.12 markus 721: xfree(comment);
722: exit(1);
723: }
724: memset(passphrase, 0, strlen(passphrase));
725: xfree(passphrase);
1.52 markus 726: public = key_from_private(private);
1.19 markus 727: key_free(private);
1.12 markus 728:
729: strlcat(identity_file, ".pub", sizeof(identity_file));
1.46 deraadt 730: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
731: if (fd == -1) {
1.12 markus 732: printf("Could not save your public key in %s\n", identity_file);
733: exit(1);
734: }
1.46 deraadt 735: f = fdopen(fd, "w");
736: if (f == NULL) {
737: printf("fdopen %s failed", identity_file);
738: exit(1);
739: }
1.19 markus 740: if (!key_write(public, f))
741: fprintf(stderr, "write key failed");
742: key_free(public);
743: fprintf(f, " %s\n", new_comment);
1.12 markus 744: fclose(f);
1.1 deraadt 745:
1.12 markus 746: xfree(comment);
1.1 deraadt 747:
1.12 markus 748: printf("The comment in your key file has been changed.\n");
749: exit(0);
1.1 deraadt 750: }
751:
1.63 itojun 752: static void
1.10 markus 753: usage(void)
754: {
1.77 jakob 755: fprintf(stderr, "Usage: %s [options]\n", __progname);
756: fprintf(stderr, "Options:\n");
757: fprintf(stderr, " -b bits Number of bits in the key to create.\n");
758: fprintf(stderr, " -c Change comment in private and public key files.\n");
759: fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n");
760: fprintf(stderr, " -f filename Filename of the key file.\n");
1.105 jakob 761: fprintf(stderr, " -g Use generic DNS resource record format.\n");
1.77 jakob 762: fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n");
763: fprintf(stderr, " -l Show fingerprint of key file.\n");
764: fprintf(stderr, " -p Change passphrase of private key file.\n");
765: fprintf(stderr, " -q Quiet.\n");
766: fprintf(stderr, " -y Read private key file and print public key.\n");
767: fprintf(stderr, " -t type Specify type of key to create.\n");
768: fprintf(stderr, " -B Show bubblebabble digest of key file.\n");
769: fprintf(stderr, " -C comment Provide new comment.\n");
770: fprintf(stderr, " -N phrase Provide new passphrase.\n");
771: fprintf(stderr, " -P phrase Provide old passphrase.\n");
1.105 jakob 772: fprintf(stderr, " -r hostname Print DNS resource record.\n");
1.77 jakob 773: #ifdef SMARTCARD
774: fprintf(stderr, " -D reader Download public key from smartcard.\n");
775: fprintf(stderr, " -U reader Upload private key to smartcard.\n");
776: #endif /* SMARTCARD */
777:
1.107 djm 778: fprintf(stderr, " -G file Generate candidates for DH-GEX moduli\n");
779: fprintf(stderr, " -T file Screen candidates for DH-GEX moduli\n");
780:
1.12 markus 781: exit(1);
1.10 markus 782: }
783:
1.13 deraadt 784: /*
785: * Main program for key management.
786: */
1.2 provos 787: int
788: main(int ac, char **av)
1.1 deraadt 789: {
1.87 djm 790: char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
1.112 djm 791: char out_file[MAXPATHLEN], *reader_id = NULL;
1.105 jakob 792: char *resource_record_hostname = NULL;
1.46 deraadt 793: Key *private, *public;
1.12 markus 794: struct passwd *pw;
795: struct stat st;
1.107 djm 796: int opt, type, fd, download = 0, memory = 0;
797: int generator_wanted = 0, trials = 100;
798: int do_gen_candidates = 0, do_screen_candidates = 0;
1.113 djm 799: int log_level = SYSLOG_LEVEL_INFO;
1.107 djm 800: BIGNUM *start = NULL;
1.12 markus 801: FILE *f;
1.33 markus 802:
1.12 markus 803: extern int optind;
804: extern char *optarg;
805:
1.26 markus 806: SSLeay_add_all_algorithms();
1.107 djm 807: log_init(av[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1.19 markus 808:
1.14 markus 809: /* we need this for the home * directory. */
1.12 markus 810: pw = getpwuid(getuid());
811: if (!pw) {
812: printf("You don't exist, go away!\n");
813: exit(1);
814: }
1.19 markus 815: if (gethostname(hostname, sizeof(hostname)) < 0) {
816: perror("gethostname");
817: exit(1);
818: }
1.14 markus 819:
1.107 djm 820: while ((opt = getopt(ac, av,
1.113 djm 821: "degiqpclBRvxXyb:f:t:U:D:P:N:C:r:g:T:G:M:S:a:W:")) != -1) {
1.12 markus 822: switch (opt) {
823: case 'b':
824: bits = atoi(optarg);
825: if (bits < 512 || bits > 32768) {
826: printf("Bits has bad value.\n");
827: exit(1);
828: }
829: break;
830: case 'l':
831: print_fingerprint = 1;
832: break;
1.49 markus 833: case 'B':
834: print_bubblebabble = 1;
835: break;
1.12 markus 836: case 'p':
837: change_passphrase = 1;
838: break;
839: case 'c':
840: change_comment = 1;
841: break;
842: case 'f':
843: strlcpy(identity_file, optarg, sizeof(identity_file));
844: have_identity = 1;
845: break;
1.105 jakob 846: case 'g':
847: print_generic = 1;
848: break;
1.12 markus 849: case 'P':
850: identity_passphrase = optarg;
851: break;
852: case 'N':
853: identity_new_passphrase = optarg;
854: break;
855: case 'C':
856: identity_comment = optarg;
857: break;
858: case 'q':
859: quiet = 1;
1.20 deraadt 860: break;
861: case 'R':
1.33 markus 862: /* unused */
863: exit(0);
1.12 markus 864: break;
1.57 markus 865: case 'e':
1.19 markus 866: case 'x':
1.57 markus 867: /* export key */
1.19 markus 868: convert_to_ssh2 = 1;
869: break;
1.57 markus 870: case 'i':
1.19 markus 871: case 'X':
1.57 markus 872: /* import key */
1.19 markus 873: convert_from_ssh2 = 1;
874: break;
875: case 'y':
876: print_public = 1;
1.47 jakob 877: break;
1.19 markus 878: case 'd':
1.33 markus 879: key_type_name = "dsa";
1.19 markus 880: break;
1.33 markus 881: case 't':
882: key_type_name = optarg;
883: break;
1.75 markus 884: case 'D':
885: download = 1;
1.76 jakob 886: case 'U':
1.75 markus 887: reader_id = optarg;
1.66 markus 888: break;
1.113 djm 889: case 'v':
890: if (log_level == SYSLOG_LEVEL_INFO)
891: log_level = SYSLOG_LEVEL_DEBUG1;
892: else {
1.113.2.1! brad 893: if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
1.113 djm 894: log_level < SYSLOG_LEVEL_DEBUG3)
895: log_level++;
896: }
897: break;
1.105 jakob 898: case 'r':
899: resource_record_hostname = optarg;
900: break;
1.107 djm 901: case 'W':
902: generator_wanted = atoi(optarg);
903: if (generator_wanted < 1)
904: fatal("Desired generator has bad value.");
905: break;
906: case 'a':
907: trials = atoi(optarg);
908: break;
909: case 'M':
910: memory = atoi(optarg);
911: break;
912: case 'G':
913: do_gen_candidates = 1;
914: strlcpy(out_file, optarg, sizeof(out_file));
915: break;
916: case 'T':
917: do_screen_candidates = 1;
918: strlcpy(out_file, optarg, sizeof(out_file));
919: break;
920: case 'S':
921: /* XXX - also compare length against bits */
922: if (BN_hex2bn(&start, optarg) == 0)
923: fatal("Invalid start point.");
924: break;
1.12 markus 925: case '?':
926: default:
927: usage();
928: }
929: }
1.113 djm 930:
931: /* reinit */
932: log_init(av[0], log_level, SYSLOG_FACILITY_USER, 1);
933:
1.12 markus 934: if (optind < ac) {
935: printf("Too many arguments.\n");
1.87 djm 936: usage();
937: }
1.12 markus 938: if (change_passphrase && change_comment) {
939: printf("Can only have one of -p and -c.\n");
940: usage();
941: }
1.49 markus 942: if (print_fingerprint || print_bubblebabble)
1.12 markus 943: do_fingerprint(pw);
944: if (change_passphrase)
945: do_change_passphrase(pw);
946: if (change_comment)
947: do_change_comment(pw);
1.19 markus 948: if (convert_to_ssh2)
949: do_convert_to_ssh2(pw);
950: if (convert_from_ssh2)
951: do_convert_from_ssh2(pw);
952: if (print_public)
953: do_print_public(pw);
1.105 jakob 954: if (resource_record_hostname != NULL) {
955: do_print_resource_record(pw, resource_record_hostname);
956: }
1.75 markus 957: if (reader_id != NULL) {
1.74 markus 958: #ifdef SMARTCARD
1.75 markus 959: if (download)
960: do_download(pw, reader_id);
961: else
962: do_upload(pw, reader_id);
1.78 jakob 963: #else /* SMARTCARD */
1.74 markus 964: fatal("no support for smartcards.");
1.78 jakob 965: #endif /* SMARTCARD */
1.107 djm 966: }
967:
968: if (do_gen_candidates) {
969: FILE *out = fopen(out_file, "w");
1.111 djm 970:
1.107 djm 971: if (out == NULL) {
972: error("Couldn't open modulus candidate file \"%s\": %s",
973: out_file, strerror(errno));
974: return (1);
975: }
976: if (gen_candidates(out, memory, bits, start) != 0)
977: fatal("modulus candidate generation failed\n");
978:
979: return (0);
980: }
981:
982: if (do_screen_candidates) {
983: FILE *in;
984: FILE *out = fopen(out_file, "w");
985:
986: if (have_identity && strcmp(identity_file, "-") != 0) {
987: if ((in = fopen(identity_file, "r")) == NULL) {
988: fatal("Couldn't open modulus candidate "
1.111 djm 989: "file \"%s\": %s", identity_file,
1.107 djm 990: strerror(errno));
991: }
992: } else
993: in = stdin;
994:
995: if (out == NULL) {
996: fatal("Couldn't open moduli file \"%s\": %s",
997: out_file, strerror(errno));
998: }
999: if (prime_test(in, out, trials, generator_wanted) != 0)
1000: fatal("modulus screening failed\n");
1.108 markus 1001: return (0);
1.75 markus 1002: }
1.12 markus 1003:
1004: arc4random_stir();
1005:
1.88 markus 1006: if (key_type_name == NULL) {
1007: printf("You must specify a key type (-t).\n");
1008: usage();
1009: }
1.35 markus 1010: type = key_type_from_name(key_type_name);
1011: if (type == KEY_UNSPEC) {
1012: fprintf(stderr, "unknown key type %s\n", key_type_name);
1013: exit(1);
1.19 markus 1014: }
1.33 markus 1015: if (!quiet)
1.35 markus 1016: printf("Generating public/private %s key pair.\n", key_type_name);
1.33 markus 1017: private = key_generate(type, bits);
1018: if (private == NULL) {
1019: fprintf(stderr, "key_generate failed");
1020: exit(1);
1021: }
1022: public = key_from_private(private);
1.12 markus 1023:
1024: if (!have_identity)
1025: ask_filename(pw, "Enter file in which to save the key");
1026:
1027: /* Create ~/.ssh directory if it doesn\'t already exist. */
1.40 markus 1028: snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1.12 markus 1029: if (strstr(identity_file, dotsshdir) != NULL &&
1030: stat(dotsshdir, &st) < 0) {
1.29 djm 1031: if (mkdir(dotsshdir, 0700) < 0)
1.12 markus 1032: error("Could not create directory '%s'.", dotsshdir);
1033: else if (!quiet)
1034: printf("Created directory '%s'.\n", dotsshdir);
1035: }
1036: /* If the file already exists, ask the user to confirm. */
1037: if (stat(identity_file, &st) >= 0) {
1038: char yesno[3];
1039: printf("%s already exists.\n", identity_file);
1040: printf("Overwrite (y/n)? ");
1041: fflush(stdout);
1042: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
1043: exit(1);
1044: if (yesno[0] != 'y' && yesno[0] != 'Y')
1045: exit(1);
1046: }
1047: /* Ask for a passphrase (twice). */
1048: if (identity_passphrase)
1049: passphrase1 = xstrdup(identity_passphrase);
1050: else if (identity_new_passphrase)
1051: passphrase1 = xstrdup(identity_new_passphrase);
1052: else {
1053: passphrase_again:
1054: passphrase1 =
1.65 markus 1055: read_passphrase("Enter passphrase (empty for no "
1056: "passphrase): ", RP_ALLOW_STDIN);
1057: passphrase2 = read_passphrase("Enter same passphrase again: ",
1058: RP_ALLOW_STDIN);
1.12 markus 1059: if (strcmp(passphrase1, passphrase2) != 0) {
1.65 markus 1060: /*
1061: * The passphrases do not match. Clear them and
1062: * retry.
1063: */
1.12 markus 1064: memset(passphrase1, 0, strlen(passphrase1));
1065: memset(passphrase2, 0, strlen(passphrase2));
1066: xfree(passphrase1);
1067: xfree(passphrase2);
1068: printf("Passphrases do not match. Try again.\n");
1069: goto passphrase_again;
1070: }
1071: /* Clear the other copy of the passphrase. */
1072: memset(passphrase2, 0, strlen(passphrase2));
1073: xfree(passphrase2);
1074: }
1075:
1076: if (identity_comment) {
1077: strlcpy(comment, identity_comment, sizeof(comment));
1078: } else {
1.18 markus 1079: /* Create default commend field for the passphrase. */
1.12 markus 1080: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
1081: }
1082:
1083: /* Save the key with the given passphrase and comment. */
1.52 markus 1084: if (!key_save_private(private, identity_file, passphrase1, comment)) {
1.56 markus 1085: printf("Saving the key failed: %s.\n", identity_file);
1.12 markus 1086: memset(passphrase1, 0, strlen(passphrase1));
1087: xfree(passphrase1);
1088: exit(1);
1089: }
1090: /* Clear the passphrase. */
1091: memset(passphrase1, 0, strlen(passphrase1));
1092: xfree(passphrase1);
1093:
1094: /* Clear the private key and the random number generator. */
1.33 markus 1095: key_free(private);
1.12 markus 1096: arc4random_stir();
1097:
1098: if (!quiet)
1099: printf("Your identification has been saved in %s.\n", identity_file);
1100:
1101: strlcat(identity_file, ".pub", sizeof(identity_file));
1.46 deraadt 1102: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1103: if (fd == -1) {
1.12 markus 1104: printf("Could not save your public key in %s\n", identity_file);
1.46 deraadt 1105: exit(1);
1106: }
1107: f = fdopen(fd, "w");
1108: if (f == NULL) {
1109: printf("fdopen %s failed", identity_file);
1.12 markus 1110: exit(1);
1111: }
1.19 markus 1112: if (!key_write(public, f))
1113: fprintf(stderr, "write key failed");
1114: fprintf(f, " %s\n", comment);
1.12 markus 1115: fclose(f);
1116:
1117: if (!quiet) {
1.50 markus 1118: char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1.19 markus 1119: printf("Your public key has been saved in %s.\n",
1120: identity_file);
1.12 markus 1121: printf("The key fingerprint is:\n");
1.50 markus 1122: printf("%s %s\n", fp, comment);
1123: xfree(fp);
1.12 markus 1124: }
1.19 markus 1125:
1126: key_free(public);
1.12 markus 1127: exit(0);
1.1 deraadt 1128: }