Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.32.2.4
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.32.2.4! jason 15: RCSID("$OpenBSD: ssh-keygen.c,v 1.60 2001/04/23 22:14:13 markus 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.32.2.4! jason 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.32.2.1 jason 27: #include "pathnames.h"
28: #include "log.h"
29: #include "readpass.h"
1.32 markus 30:
1.19 markus 31: /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
1.1 deraadt 32: int bits = 1024;
33:
1.14 markus 34: /*
35: * Flag indicating that we just want to change the passphrase. This can be
36: * set on the command line.
37: */
1.1 deraadt 38: int change_passphrase = 0;
39:
1.14 markus 40: /*
41: * Flag indicating that we just want to change the comment. This can be set
42: * on the command line.
43: */
1.1 deraadt 44: int change_comment = 0;
45:
1.2 provos 46: int quiet = 0;
47:
1.8 markus 48: /* Flag indicating that we just want to see the key fingerprint */
49: int print_fingerprint = 0;
1.32.2.3 jason 50: int print_bubblebabble = 0;
1.8 markus 51:
1.10 markus 52: /* The identity file name, given on the command line or entered by the user. */
53: char identity_file[1024];
54: int have_identity = 0;
1.1 deraadt 55:
56: /* This is set to the passphrase if given on the command line. */
57: char *identity_passphrase = NULL;
58:
59: /* This is set to the new passphrase if given on the command line. */
60: char *identity_new_passphrase = NULL;
61:
62: /* This is set to the new comment if given on the command line. */
63: char *identity_comment = NULL;
64:
1.19 markus 65: /* Dump public key file in format used by real and the original SSH 2 */
66: int convert_to_ssh2 = 0;
67: int convert_from_ssh2 = 0;
68: int print_public = 0;
1.32.2.1 jason 69:
70: /* default to RSA for SSH-1 */
71: char *key_type_name = "rsa1";
1.19 markus 72:
1.10 markus 73: /* argv0 */
74: extern char *__progname;
1.1 deraadt 75:
1.19 markus 76: char hostname[MAXHOSTNAMELEN];
77:
1.10 markus 78: void
79: ask_filename(struct passwd *pw, const char *prompt)
1.1 deraadt 80: {
1.12 markus 81: char buf[1024];
1.32.2.1 jason 82: char *name = NULL;
83:
84: switch (key_type_from_name(key_type_name)) {
85: case KEY_RSA1:
86: name = _PATH_SSH_CLIENT_IDENTITY;
87: break;
88: case KEY_DSA:
89: name = _PATH_SSH_CLIENT_ID_DSA;
90: break;
91: case KEY_RSA:
92: name = _PATH_SSH_CLIENT_ID_RSA;
93: break;
94: default:
95: fprintf(stderr, "bad key type");
96: exit(1);
97: break;
98: }
99: snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
100: fprintf(stderr, "%s (%s): ", prompt, identity_file);
101: fflush(stderr);
1.12 markus 102: if (fgets(buf, sizeof(buf), stdin) == NULL)
103: exit(1);
104: if (strchr(buf, '\n'))
105: *strchr(buf, '\n') = 0;
106: if (strcmp(buf, "") != 0)
107: strlcpy(identity_file, buf, sizeof(identity_file));
108: have_identity = 1;
1.7 markus 109: }
110:
1.32.2.4! jason 111: Key *
! 112: try_load_pem_key(char *filename)
1.19 markus 113: {
1.32.2.4! jason 114: char *pass;
! 115: Key *prv;
! 116:
! 117: prv = key_load_private(filename, "", NULL);
! 118: if (prv == NULL) {
! 119: pass = read_passphrase("Enter passphrase: ", 1);
! 120: prv = key_load_private(filename, pass, NULL);
1.19 markus 121: memset(pass, 0, strlen(pass));
122: xfree(pass);
123: }
1.32.2.4! jason 124: return prv;
1.19 markus 125: }
126:
1.32 markus 127: #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
128: #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
129: #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
1.32.2.1 jason 130: #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
1.19 markus 131:
132: void
133: do_convert_to_ssh2(struct passwd *pw)
134: {
135: Key *k;
136: int len;
1.32.2.1 jason 137: u_char *blob;
1.19 markus 138: struct stat st;
139:
140: if (!have_identity)
141: ask_filename(pw, "Enter file in which the key is");
142: if (stat(identity_file, &st) < 0) {
143: perror(identity_file);
144: exit(1);
145: }
1.32.2.4! jason 146: if ((k = key_load_public(identity_file, NULL)) == NULL) {
! 147: if ((k = try_load_pem_key(identity_file)) == NULL) {
! 148: fprintf(stderr, "load failed\n");
! 149: exit(1);
! 150: }
1.19 markus 151: }
1.32.2.1 jason 152: key_to_blob(k, &blob, &len);
1.32 markus 153: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
1.19 markus 154: fprintf(stdout,
1.32 markus 155: "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
156: key_size(k), key_type(k),
1.19 markus 157: pw->pw_name, hostname);
158: dump_base64(stdout, blob, len);
1.32 markus 159: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
1.19 markus 160: key_free(k);
1.21 markus 161: xfree(blob);
1.19 markus 162: exit(0);
163: }
164:
165: void
1.32 markus 166: buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
167: {
168: int bits = buffer_get_int(b);
169: int bytes = (bits + 7) / 8;
1.32.2.4! jason 170:
1.32 markus 171: if (buffer_len(b) < bytes)
1.32.2.4! jason 172: fatal("buffer_get_bignum_bits: input buffer too small: "
! 173: "need %d have %d", bytes, buffer_len(b));
1.32.2.1 jason 174: BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
1.32 markus 175: buffer_consume(b, bytes);
176: }
177:
178: Key *
179: do_convert_private_ssh2_from_blob(char *blob, int blen)
180: {
181: Buffer b;
182: Key *key = NULL;
1.32.2.4! jason 183: int ignore, magic, rlen, ktype;
1.32 markus 184: char *type, *cipher;
185:
186: buffer_init(&b);
187: buffer_append(&b, blob, blen);
188:
189: magic = buffer_get_int(&b);
190: if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
191: error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
192: buffer_free(&b);
193: return NULL;
194: }
195: ignore = buffer_get_int(&b);
196: type = buffer_get_string(&b, NULL);
197: cipher = buffer_get_string(&b, NULL);
198: ignore = buffer_get_int(&b);
199: ignore = buffer_get_int(&b);
200: ignore = buffer_get_int(&b);
201:
202: if (strcmp(cipher, "none") != 0) {
203: error("unsupported cipher %s", cipher);
204: xfree(cipher);
205: buffer_free(&b);
1.32.2.4! jason 206: xfree(type);
1.32 markus 207: return NULL;
208: }
209: xfree(cipher);
210:
1.32.2.4! jason 211: if (strstr(type, "dsa")) {
! 212: ktype = KEY_DSA;
! 213: } else if (strstr(type, "rsa")) {
! 214: ktype = KEY_RSA;
! 215: } else {
! 216: xfree(type);
1.32 markus 217: return NULL;
218: }
1.32.2.4! jason 219: key = key_new_private(ktype);
! 220: xfree(type);
! 221:
! 222: switch (key->type) {
! 223: case KEY_DSA:
! 224: buffer_get_bignum_bits(&b, key->dsa->p);
! 225: buffer_get_bignum_bits(&b, key->dsa->g);
! 226: buffer_get_bignum_bits(&b, key->dsa->q);
! 227: buffer_get_bignum_bits(&b, key->dsa->pub_key);
! 228: buffer_get_bignum_bits(&b, key->dsa->priv_key);
! 229: break;
! 230: case KEY_RSA:
! 231: if (!BN_set_word(key->rsa->e, (u_long) buffer_get_char(&b))) {
! 232: buffer_free(&b);
! 233: key_free(key);
! 234: return NULL;
! 235: }
! 236: buffer_get_bignum_bits(&b, key->rsa->d);
! 237: buffer_get_bignum_bits(&b, key->rsa->n);
! 238: buffer_get_bignum_bits(&b, key->rsa->iqmp);
! 239: buffer_get_bignum_bits(&b, key->rsa->q);
! 240: buffer_get_bignum_bits(&b, key->rsa->p);
! 241: generate_additional_parameters(key->rsa);
! 242: break;
! 243: }
1.32 markus 244: rlen = buffer_len(&b);
245: if(rlen != 0)
1.32.2.4! jason 246: error("do_convert_private_ssh2_from_blob: "
! 247: "remaining bytes in key blob %d", rlen);
1.32 markus 248: buffer_free(&b);
1.32.2.4! jason 249: #ifdef DEBUG_PK
! 250: {
! 251: u_int slen;
! 252: u_char *sig, data[10] = "abcde12345";
! 253:
! 254: key_sign(key, &sig, &slen, data, sizeof data);
! 255: key_verify(key, sig, slen, data, sizeof data);
! 256: xfree(sig);
! 257: }
! 258: #endif
1.32 markus 259: return key;
260: }
261:
262: void
1.19 markus 263: do_convert_from_ssh2(struct passwd *pw)
264: {
265: Key *k;
266: int blen;
267: char line[1024], *p;
268: char blob[8096];
269: char encoded[8096];
270: struct stat st;
1.32 markus 271: int escaped = 0, private = 0, ok;
1.19 markus 272: FILE *fp;
273:
274: if (!have_identity)
275: ask_filename(pw, "Enter file in which the key is");
276: if (stat(identity_file, &st) < 0) {
277: perror(identity_file);
278: exit(1);
279: }
280: fp = fopen(identity_file, "r");
281: if (fp == NULL) {
282: perror(identity_file);
283: exit(1);
284: }
285: encoded[0] = '\0';
286: while (fgets(line, sizeof(line), fp)) {
1.25 markus 287: if (!(p = strchr(line, '\n'))) {
288: fprintf(stderr, "input line too long.\n");
289: exit(1);
290: }
291: if (p > line && p[-1] == '\\')
292: escaped++;
1.19 markus 293: if (strncmp(line, "----", 4) == 0 ||
294: strstr(line, ": ") != NULL) {
1.32 markus 295: if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
296: private = 1;
1.32.2.4! jason 297: /* fprintf(stderr, "ignore: %s", line); */
1.19 markus 298: continue;
299: }
1.25 markus 300: if (escaped) {
301: escaped--;
1.32.2.4! jason 302: /* fprintf(stderr, "escaped: %s", line); */
1.25 markus 303: continue;
1.19 markus 304: }
305: *p = '\0';
306: strlcat(encoded, line, sizeof(encoded));
307: }
1.32.2.1 jason 308: blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
1.19 markus 309: if (blen < 0) {
310: fprintf(stderr, "uudecode failed.\n");
311: exit(1);
312: }
1.32 markus 313: k = private ?
314: do_convert_private_ssh2_from_blob(blob, blen) :
1.32.2.1 jason 315: key_from_blob(blob, blen);
1.32 markus 316: if (k == NULL) {
317: fprintf(stderr, "decode blob failed.\n");
318: exit(1);
319: }
320: ok = private ?
1.32.2.4! jason 321: (k->type == KEY_DSA ?
! 322: PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
! 323: PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
1.32 markus 324: key_write(k, stdout);
325: if (!ok) {
326: fprintf(stderr, "key write failed");
327: exit(1);
328: }
1.19 markus 329: key_free(k);
330: fprintf(stdout, "\n");
331: fclose(fp);
332: exit(0);
333: }
334:
335: void
336: do_print_public(struct passwd *pw)
337: {
1.32.2.4! jason 338: Key *prv;
1.19 markus 339: struct stat st;
340:
341: if (!have_identity)
342: ask_filename(pw, "Enter file in which the key is");
343: if (stat(identity_file, &st) < 0) {
344: perror(identity_file);
345: exit(1);
346: }
1.32.2.4! jason 347: prv = try_load_pem_key(identity_file);
! 348: if (prv == NULL) {
1.19 markus 349: fprintf(stderr, "load failed\n");
350: exit(1);
351: }
1.32.2.4! jason 352: if (!key_write(prv, stdout))
1.19 markus 353: fprintf(stderr, "key_write failed");
1.32.2.4! jason 354: key_free(prv);
1.19 markus 355: fprintf(stdout, "\n");
356: exit(0);
357: }
358:
1.7 markus 359: void
1.8 markus 360: do_fingerprint(struct passwd *pw)
361: {
1.15 markus 362: FILE *f;
1.19 markus 363: Key *public;
1.32.2.3 jason 364: char *comment = NULL, *cp, *ep, line[16*1024], *fp;
1.32.2.4! jason 365: int i, skip = 0, num = 1, invalid = 1, rep, fptype;
1.12 markus 366: struct stat st;
367:
1.32.2.4! jason 368: fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
! 369: rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
1.32.2.3 jason 370:
1.12 markus 371: if (!have_identity)
372: ask_filename(pw, "Enter file in which the key is");
373: if (stat(identity_file, &st) < 0) {
374: perror(identity_file);
375: exit(1);
376: }
1.32.2.4! jason 377: public = key_load_public(identity_file, &comment);
! 378: if (public != NULL) {
! 379: fp = key_fingerprint(public, fptype, rep);
! 380: printf("%d %s %s\n", key_size(public), fp, comment);
1.19 markus 381: key_free(public);
1.32.2.1 jason 382: xfree(comment);
1.32.2.3 jason 383: xfree(fp);
1.15 markus 384: exit(0);
385: }
1.32.2.4! jason 386: if (comment)
! 387: xfree(comment);
1.15 markus 388:
389: f = fopen(identity_file, "r");
390: if (f != NULL) {
391: while (fgets(line, sizeof(line), f)) {
392: i = strlen(line) - 1;
393: if (line[i] != '\n') {
394: error("line %d too long: %.40s...", num, line);
395: skip = 1;
396: continue;
397: }
398: num++;
399: if (skip) {
400: skip = 0;
401: continue;
402: }
403: line[i] = '\0';
404:
405: /* Skip leading whitespace, empty and comment lines. */
406: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
407: ;
408: if (!*cp || *cp == '\n' || *cp == '#')
409: continue ;
410: i = strtol(cp, &ep, 10);
411: if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
412: int quoted = 0;
413: comment = cp;
414: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
415: if (*cp == '\\' && cp[1] == '"')
416: cp++; /* Skip both */
417: else if (*cp == '"')
418: quoted = !quoted;
419: }
420: if (!*cp)
421: continue;
422: *cp++ = '\0';
423: }
424: ep = cp;
1.32.2.1 jason 425: public = key_new(KEY_RSA1);
426: if (key_read(public, &cp) != 1) {
427: cp = ep;
428: key_free(public);
429: public = key_new(KEY_UNSPEC);
430: if (key_read(public, &cp) != 1) {
431: key_free(public);
432: continue;
433: }
1.12 markus 434: }
1.32.2.1 jason 435: comment = *cp ? cp : comment;
1.32.2.4! jason 436: fp = key_fingerprint(public, fptype, rep);
1.32.2.3 jason 437: printf("%d %s %s\n", key_size(public), fp,
1.32.2.1 jason 438: comment ? comment : "no comment");
1.32.2.3 jason 439: xfree(fp);
1.32.2.4! jason 440: key_free(public);
1.32.2.1 jason 441: invalid = 0;
1.12 markus 442: }
1.15 markus 443: fclose(f);
444: }
445: if (invalid) {
446: printf("%s is not a valid key file.\n", identity_file);
447: exit(1);
1.12 markus 448: }
449: exit(0);
1.8 markus 450: }
451:
1.13 deraadt 452: /*
453: * Perform changing a passphrase. The argument is the passwd structure
454: * for the current user.
455: */
1.8 markus 456: void
1.7 markus 457: do_change_passphrase(struct passwd *pw)
458: {
1.12 markus 459: char *comment;
460: char *old_passphrase, *passphrase1, *passphrase2;
461: struct stat st;
1.19 markus 462: Key *private;
1.12 markus 463:
464: if (!have_identity)
465: ask_filename(pw, "Enter file in which the key is");
466: if (stat(identity_file, &st) < 0) {
467: perror(identity_file);
468: exit(1);
469: }
470: /* Try to load the file with empty passphrase. */
1.32.2.4! jason 471: private = key_load_private(identity_file, "", &comment);
! 472: if (private == NULL) {
1.12 markus 473: if (identity_passphrase)
474: old_passphrase = xstrdup(identity_passphrase);
475: else
476: old_passphrase = read_passphrase("Enter old passphrase: ", 1);
1.32.2.4! jason 477: private = key_load_private(identity_file, old_passphrase , &comment);
! 478: memset(old_passphrase, 0, strlen(old_passphrase));
! 479: xfree(old_passphrase);
! 480: if (private == NULL) {
1.12 markus 481: printf("Bad passphrase.\n");
482: exit(1);
483: }
484: }
485: printf("Key has comment '%s'\n", comment);
486:
487: /* Ask the new passphrase (twice). */
488: if (identity_new_passphrase) {
489: passphrase1 = xstrdup(identity_new_passphrase);
490: passphrase2 = NULL;
491: } else {
492: passphrase1 =
493: read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
494: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
495:
496: /* Verify that they are the same. */
497: if (strcmp(passphrase1, passphrase2) != 0) {
498: memset(passphrase1, 0, strlen(passphrase1));
499: memset(passphrase2, 0, strlen(passphrase2));
500: xfree(passphrase1);
501: xfree(passphrase2);
502: printf("Pass phrases do not match. Try again.\n");
503: exit(1);
504: }
505: /* Destroy the other copy. */
506: memset(passphrase2, 0, strlen(passphrase2));
507: xfree(passphrase2);
508: }
509:
510: /* Save the file using the new passphrase. */
1.32.2.4! jason 511: if (!key_save_private(private, identity_file, passphrase1, comment)) {
! 512: printf("Saving the key failed: %s.\n", identity_file);
1.12 markus 513: memset(passphrase1, 0, strlen(passphrase1));
514: xfree(passphrase1);
1.19 markus 515: key_free(private);
1.12 markus 516: xfree(comment);
517: exit(1);
518: }
519: /* Destroy the passphrase and the copy of the key in memory. */
520: memset(passphrase1, 0, strlen(passphrase1));
521: xfree(passphrase1);
1.19 markus 522: key_free(private); /* Destroys contents */
1.12 markus 523: xfree(comment);
1.1 deraadt 524:
1.12 markus 525: printf("Your identification has been saved with the new passphrase.\n");
526: exit(0);
1.1 deraadt 527: }
528:
1.13 deraadt 529: /*
530: * Change the comment of a private key file.
531: */
1.2 provos 532: void
533: do_change_comment(struct passwd *pw)
1.1 deraadt 534: {
1.32.2.3 jason 535: char new_comment[1024], *comment, *passphrase;
1.32.2.4! jason 536: Key *private;
! 537: Key *public;
1.12 markus 538: struct stat st;
539: FILE *f;
1.32.2.3 jason 540: int fd;
1.12 markus 541:
542: if (!have_identity)
543: ask_filename(pw, "Enter file in which the key is");
544: if (stat(identity_file, &st) < 0) {
545: perror(identity_file);
546: exit(1);
547: }
1.32.2.4! jason 548: private = key_load_private(identity_file, "", &comment);
! 549: if (private == NULL) {
1.12 markus 550: if (identity_passphrase)
551: passphrase = xstrdup(identity_passphrase);
552: else if (identity_new_passphrase)
553: passphrase = xstrdup(identity_new_passphrase);
554: else
555: passphrase = read_passphrase("Enter passphrase: ", 1);
556: /* Try to load using the passphrase. */
1.32.2.4! jason 557: private = key_load_private(identity_file, passphrase, &comment);
! 558: if (private == NULL) {
1.12 markus 559: memset(passphrase, 0, strlen(passphrase));
560: xfree(passphrase);
561: printf("Bad passphrase.\n");
562: exit(1);
563: }
1.32.2.4! jason 564: } else {
! 565: passphrase = xstrdup("");
1.12 markus 566: }
1.32.2.4! jason 567: if (private->type != KEY_RSA1) {
! 568: fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
! 569: key_free(private);
! 570: exit(1);
! 571: }
1.12 markus 572: printf("Key now has comment '%s'\n", comment);
573:
574: if (identity_comment) {
575: strlcpy(new_comment, identity_comment, sizeof(new_comment));
576: } else {
577: printf("Enter new comment: ");
578: fflush(stdout);
579: if (!fgets(new_comment, sizeof(new_comment), stdin)) {
580: memset(passphrase, 0, strlen(passphrase));
1.19 markus 581: key_free(private);
1.12 markus 582: exit(1);
583: }
584: if (strchr(new_comment, '\n'))
585: *strchr(new_comment, '\n') = 0;
586: }
587:
588: /* Save the file using the new passphrase. */
1.32.2.4! jason 589: if (!key_save_private(private, identity_file, passphrase, new_comment)) {
! 590: printf("Saving the key failed: %s.\n", identity_file);
1.12 markus 591: memset(passphrase, 0, strlen(passphrase));
592: xfree(passphrase);
1.19 markus 593: key_free(private);
1.12 markus 594: xfree(comment);
595: exit(1);
596: }
597: memset(passphrase, 0, strlen(passphrase));
598: xfree(passphrase);
1.32.2.4! jason 599: public = key_from_private(private);
1.19 markus 600: key_free(private);
1.12 markus 601:
602: strlcat(identity_file, ".pub", sizeof(identity_file));
1.32.2.3 jason 603: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
604: if (fd == -1) {
1.12 markus 605: printf("Could not save your public key in %s\n", identity_file);
606: exit(1);
607: }
1.32.2.3 jason 608: f = fdopen(fd, "w");
609: if (f == NULL) {
610: printf("fdopen %s failed", identity_file);
611: exit(1);
612: }
1.19 markus 613: if (!key_write(public, f))
614: fprintf(stderr, "write key failed");
615: key_free(public);
616: fprintf(f, " %s\n", new_comment);
1.12 markus 617: fclose(f);
1.1 deraadt 618:
1.12 markus 619: xfree(comment);
1.1 deraadt 620:
1.12 markus 621: printf("The comment in your key file has been changed.\n");
622: exit(0);
1.1 deraadt 623: }
624:
1.10 markus 625: void
626: usage(void)
627: {
1.32.2.4! jason 628: printf("Usage: %s [-ceilpqyB] [-t type] [-b bits] [-f file] [-C comment] "
1.32.2.3 jason 629: "[-N new-pass] [-P pass]\n", __progname);
1.12 markus 630: exit(1);
1.10 markus 631: }
632:
1.13 deraadt 633: /*
634: * Main program for key management.
635: */
1.2 provos 636: int
637: main(int ac, char **av)
1.1 deraadt 638: {
1.12 markus 639: char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
1.32.2.3 jason 640: Key *private, *public;
1.12 markus 641: struct passwd *pw;
1.32.2.3 jason 642: int opt, type, fd;
1.12 markus 643: struct stat st;
644: FILE *f;
1.32.2.1 jason 645:
1.12 markus 646: extern int optind;
647: extern char *optarg;
648:
1.26 markus 649: SSLeay_add_all_algorithms();
1.19 markus 650:
1.14 markus 651: /* we need this for the home * directory. */
1.12 markus 652: pw = getpwuid(getuid());
653: if (!pw) {
654: printf("You don't exist, go away!\n");
655: exit(1);
656: }
1.19 markus 657: if (gethostname(hostname, sizeof(hostname)) < 0) {
658: perror("gethostname");
659: exit(1);
660: }
1.14 markus 661:
1.32.2.4! jason 662: while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:P:N:C:")) != -1) {
1.12 markus 663: switch (opt) {
664: case 'b':
665: bits = atoi(optarg);
666: if (bits < 512 || bits > 32768) {
667: printf("Bits has bad value.\n");
668: exit(1);
669: }
670: break;
671:
672: case 'l':
673: print_fingerprint = 1;
674: break;
675:
1.32.2.3 jason 676: case 'B':
677: print_bubblebabble = 1;
678: break;
679:
1.12 markus 680: case 'p':
681: change_passphrase = 1;
682: break;
683:
684: case 'c':
685: change_comment = 1;
686: break;
687:
688: case 'f':
689: strlcpy(identity_file, optarg, sizeof(identity_file));
690: have_identity = 1;
691: break;
692:
693: case 'P':
694: identity_passphrase = optarg;
695: break;
696:
697: case 'N':
698: identity_new_passphrase = optarg;
699: break;
700:
701: case 'C':
702: identity_comment = optarg;
703: break;
704:
705: case 'q':
706: quiet = 1;
1.20 deraadt 707: break;
708:
709: case 'R':
1.32.2.1 jason 710: /* unused */
711: exit(0);
1.12 markus 712: break;
713:
1.32.2.4! jason 714: case 'e':
1.19 markus 715: case 'x':
1.32.2.4! jason 716: /* export key */
1.19 markus 717: convert_to_ssh2 = 1;
718: break;
719:
1.32.2.4! jason 720: case 'i':
1.19 markus 721: case 'X':
1.32.2.4! jason 722: /* import key */
1.19 markus 723: convert_from_ssh2 = 1;
724: break;
725:
726: case 'y':
727: print_public = 1;
728: break;
729:
730: case 'd':
1.32.2.1 jason 731: key_type_name = "dsa";
732: break;
733:
734: case 't':
735: key_type_name = optarg;
1.19 markus 736: break;
737:
1.12 markus 738: case '?':
739: default:
740: usage();
741: }
742: }
743: if (optind < ac) {
744: printf("Too many arguments.\n");
745: usage();
746: }
747: if (change_passphrase && change_comment) {
748: printf("Can only have one of -p and -c.\n");
749: usage();
750: }
1.32.2.3 jason 751: if (print_fingerprint || print_bubblebabble)
1.12 markus 752: do_fingerprint(pw);
753: if (change_passphrase)
754: do_change_passphrase(pw);
755: if (change_comment)
756: do_change_comment(pw);
1.19 markus 757: if (convert_to_ssh2)
758: do_convert_to_ssh2(pw);
759: if (convert_from_ssh2)
760: do_convert_from_ssh2(pw);
761: if (print_public)
762: do_print_public(pw);
1.12 markus 763:
764: arc4random_stir();
765:
1.32.2.1 jason 766: type = key_type_from_name(key_type_name);
767: if (type == KEY_UNSPEC) {
768: fprintf(stderr, "unknown key type %s\n", key_type_name);
769: exit(1);
770: }
771: if (!quiet)
772: printf("Generating public/private %s key pair.\n", key_type_name);
773: private = key_generate(type, bits);
774: if (private == NULL) {
775: fprintf(stderr, "key_generate failed");
776: exit(1);
1.19 markus 777: }
1.32.2.1 jason 778: public = key_from_private(private);
1.12 markus 779:
780: if (!have_identity)
781: ask_filename(pw, "Enter file in which to save the key");
782:
783: /* Create ~/.ssh directory if it doesn\'t already exist. */
1.32.2.1 jason 784: snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1.12 markus 785: if (strstr(identity_file, dotsshdir) != NULL &&
786: stat(dotsshdir, &st) < 0) {
1.29 djm 787: if (mkdir(dotsshdir, 0700) < 0)
1.12 markus 788: error("Could not create directory '%s'.", dotsshdir);
789: else if (!quiet)
790: printf("Created directory '%s'.\n", dotsshdir);
791: }
792: /* If the file already exists, ask the user to confirm. */
793: if (stat(identity_file, &st) >= 0) {
794: char yesno[3];
795: printf("%s already exists.\n", identity_file);
796: printf("Overwrite (y/n)? ");
797: fflush(stdout);
798: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
799: exit(1);
800: if (yesno[0] != 'y' && yesno[0] != 'Y')
801: exit(1);
802: }
803: /* Ask for a passphrase (twice). */
804: if (identity_passphrase)
805: passphrase1 = xstrdup(identity_passphrase);
806: else if (identity_new_passphrase)
807: passphrase1 = xstrdup(identity_new_passphrase);
808: else {
809: passphrase_again:
810: passphrase1 =
811: read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
812: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
813: if (strcmp(passphrase1, passphrase2) != 0) {
814: /* The passphrases do not match. Clear them and retry. */
815: memset(passphrase1, 0, strlen(passphrase1));
816: memset(passphrase2, 0, strlen(passphrase2));
817: xfree(passphrase1);
818: xfree(passphrase2);
819: printf("Passphrases do not match. Try again.\n");
820: goto passphrase_again;
821: }
822: /* Clear the other copy of the passphrase. */
823: memset(passphrase2, 0, strlen(passphrase2));
824: xfree(passphrase2);
825: }
826:
827: if (identity_comment) {
828: strlcpy(comment, identity_comment, sizeof(comment));
829: } else {
1.18 markus 830: /* Create default commend field for the passphrase. */
1.12 markus 831: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
832: }
833:
834: /* Save the key with the given passphrase and comment. */
1.32.2.4! jason 835: if (!key_save_private(private, identity_file, passphrase1, comment)) {
! 836: printf("Saving the key failed: %s.\n", identity_file);
1.12 markus 837: memset(passphrase1, 0, strlen(passphrase1));
838: xfree(passphrase1);
839: exit(1);
840: }
841: /* Clear the passphrase. */
842: memset(passphrase1, 0, strlen(passphrase1));
843: xfree(passphrase1);
844:
845: /* Clear the private key and the random number generator. */
1.32.2.1 jason 846: key_free(private);
1.12 markus 847: arc4random_stir();
848:
849: if (!quiet)
850: printf("Your identification has been saved in %s.\n", identity_file);
851:
852: strlcat(identity_file, ".pub", sizeof(identity_file));
1.32.2.3 jason 853: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
854: if (fd == -1) {
1.12 markus 855: printf("Could not save your public key in %s\n", identity_file);
856: exit(1);
857: }
1.32.2.3 jason 858: f = fdopen(fd, "w");
859: if (f == NULL) {
860: printf("fdopen %s failed", identity_file);
861: exit(1);
862: }
1.19 markus 863: if (!key_write(public, f))
864: fprintf(stderr, "write key failed");
865: fprintf(f, " %s\n", comment);
1.12 markus 866: fclose(f);
867:
868: if (!quiet) {
1.32.2.3 jason 869: char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1.19 markus 870: printf("Your public key has been saved in %s.\n",
871: identity_file);
1.12 markus 872: printf("The key fingerprint is:\n");
1.32.2.3 jason 873: printf("%s %s\n", fp, comment);
874: xfree(fp);
1.12 markus 875: }
1.19 markus 876:
877: key_free(public);
1.12 markus 878: exit(0);
1.1 deraadt 879: }